Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • bh 444 posts 1544 karma points
    Mar 10, 2022 @ 13:36
    bh
    0

    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:

    1. When I setup my controller, I still got a 404.
    2. 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.

  • Michael Cleverly 8 posts 120 karma points
    Mar 11, 2022 @ 07:28
    Michael Cleverly
    1

    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:

    vm.UmbracoHelper = Umbraco;
    

    Let me know if this answers your question

  • bh 444 posts 1544 karma points
    Mar 11, 2022 @ 14:45
    bh
    0

    @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:

    $.ajax({
                url: "/projects",
                Type: 'get',
                data: {
                    page: currentPage,
                    pageSize: pageSize
                },
                success: function (html) {
                    $('#more-container').append($('#portfolio-more', $(html)));
                    $(this).data('current-page', nextPage);
                }
            });
    

    /Controllers/ProjectListController.cs:

    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>
    
  • Michael Cleverly 8 posts 120 karma points
    Mar 11, 2022 @ 18:39
    Michael Cleverly
    100

    To reach the surface controller from an ajax call, you need the following path:

    /umbraco/surface/projectslist/{yourAction}

  • Moran 285 posts 934 karma points
    Dec 27, 2022 @ 14:54
    Moran
    0

    Hi I can access this only using the "Get" action. Can I use this for a "Post" action?

  • bh 444 posts 1544 karma points
    Mar 11, 2022 @ 20:20
    bh
    0

    Here's the final controller! Many thanks to @michaelcleverly!!

    namespace myapplication.Controllers
    {
        public class ProjectsListController : SurfaceController
        {
            [Route("projects")]
            public ActionResult GetProjects()
            {
                var root = (Home)Umbraco.Content(1066);
                var projectsRoot = root.DescendantOfType("Portfolio");
    
                return PartialView("~/Views/Partials/PortfolioListMore.cshtml", projectsRoot);
            }
        }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft