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);
            }
        }
    }
    
  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies