I'm attempting to return a PartialView to an ajax call. I ran into a situation where you can't browse directly to a PartialView. Which makes sense. Fortunately @carlosmosqueda got me looking at creating a controller to route to my PartialView. I've looked at ApiController, SurfaceController and RenderMvcController.
Best I can tell SurfaceController is the one I need. But, two things:
When I setup my controller, I still got a 404.
I couldn't figure out how to pass parameters from my SurfaceController to my PartialView.
My first SurfaceController - the issue with this is PartialView doesn't support ViewData. So this code won't compile without error.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Umbraco.Web.Mvc;
namespace maypplication.Controllers
{
[Route("projects/[action]")]
public class ProjectsListController : SurfaceController
{
[Route("projects/{page?}/{pageSize?}")]
public PartialViewResult GetProjects(int page, int pageSize)
{
return PartialView("/views/partials/PortfolioListMore.cshtml", new Umbraco.Web.Models.ContentModel(CurrentPage), new ViewDataDictionary { { "page", page }, { "pageSize", pageSize } });
}
}
}
My second attempt at the controller - This compiles, but I get a 404 and I don't see how to pass ViewData to the PartialView.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Umbraco.Web.Mvc;
namespace myapplication.Controllers
{
[Route("projects/[action]")]
public class ProjectsListController : SurfaceController
{
public PartialViewResult GetProjects()
{
return PartialView("/views/partials/PortfolioListMore.cshtml", new Umbraco.Web.Models.ContentModel(CurrentPage));
}
}
}
I would appreciate any advice on how to pass parameters to a PartialView from an ajax call via a SurfaceController (I think) and return that PartialView.
The thing to keep in mind when working with surface-controllers and Ajax, is that you will not have the Umbraco context available in the controller action, including culture context. So if you have multiple root nodes and/or cultures, you need to pass those parameters to the action. Here is an example:
private readonly IVariationContextAccessor _variationContextAccessor;
public ProjectsListController (IVariationContextAccessor variationContextAccessor)
{
_variationContextAccessor = variationContextAccessor;
}
[Route("projects/{page?}/{pageSize?}")]
public ActionResult GetProjects(int id, int rootId, string culture)
{
var cultureInfo = new CultureInfo(culture);
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
_variationContextAccessor.VariationContext = new VariationContext(culture);
var root = (YourRootModel) Umbraco.Content(rootId);
var projectsRoot = (ProjectsRootModel)Umbraco.ContentAtRoot().First(x => x.IsDocumentType("projectsRoot"));
var projects= projectsRoot.Descendants<Project>().ToList();
var vm = new YourViewModel()
{
Root = root,
Projects= projects,
Culture = culture
};
return PartialView("~/Views/Partials/_Projects.cshtml", vm);
}
And your partial view will simply be a normal .cshtml with a viewmodel. If you need to use the Umbraco helper in the partial view, you can also pass that to the viewmodel:
using System.Linq;
using System.Web.Mvc;
using Umbraco.Web.Mvc;
using Umbraco.Web;
using myapplication.ModelsLibrary;
namespace myapplication.Controllers
{
public class ProjectsListController : SurfaceController
{
[Route("projects")]
public ActionResult GetProjects()
{
var projectsRoot = (Portfolio)Umbraco.ContentAtRoot().First(x => x.IsDocumentType("Portfolio"));
return PartialView("~/Views/Partials/PortfolioListMore.cshtml", projectsRoot);
}
}
}
/Views/Partials/PortfolioListMore.cshtml
@inherits Umbraco.Web.Mvc.UmbracoViewPage<myapplication.ModelsLibrary.Portfolio>
@{
Layout = null;
var page = 1;
if (!string.IsNullOrEmpty(Request.QueryString["page"]))
{
page = Convert.ToInt32(Request.QueryString["page"]);
}
var pageSize = 1;
if (!string.IsNullOrEmpty(Request.QueryString["pageSize"]))
{
pageSize = Convert.ToInt32(Request.QueryString["pageSize"]);
}
var projects = Model.Children.Where(x => x.IsVisible()).Skip(page * pageSize).Take(pageSize);
}
<div id="portfolio-more">
@foreach(myapplication.ModelsLibrary.Project p in projects)
{
<a href="@p.Url()" class="row list-item ">
<div class="col-12 col-lg-6">
<h3>@p.Name</h3>
</div>
</a>
}
</div>
SurfaceController to Return PartialView
I'm attempting to return a PartialView to an ajax call. I ran into a situation where you can't browse directly to a PartialView. Which makes sense. Fortunately @carlosmosqueda got me looking at creating a controller to route to my PartialView. I've looked at ApiController, SurfaceController and RenderMvcController.
Best I can tell SurfaceController is the one I need. But, two things:
My first SurfaceController - the issue with this is PartialView doesn't support ViewData. So this code won't compile without error.
My second attempt at the controller - This compiles, but I get a 404 and I don't see how to pass ViewData to the PartialView.
I would appreciate any advice on how to pass parameters to a PartialView from an ajax call via a SurfaceController (I think) and return that PartialView.
The thing to keep in mind when working with surface-controllers and Ajax, is that you will not have the Umbraco context available in the controller action, including culture context. So if you have multiple root nodes and/or cultures, you need to pass those parameters to the action. Here is an example:
And your partial view will simply be a normal .cshtml with a viewmodel. If you need to use the Umbraco helper in the partial view, you can also pass that to the viewmodel:
Let me know if this answers your question
@MichaelCleverly many thanks for taking the time to respond.
Using your response as inspiration...I'm still getting a 404 on the ajax call.
my ajax call:
/Controllers/ProjectListController.cs:
/Views/Partials/PortfolioListMore.cshtml
To reach the surface controller from an ajax call, you need the following path:
/umbraco/surface/projectslist/{yourAction}
Hi I can access this only using the "Get" action. Can I use this for a "Post" action?
Here's the final controller! Many thanks to @michaelcleverly!!
is working on a reply...