Copied to clipboard

Flag this post as spam?

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


  • jho 3 posts 35 karma points
    Jan 10, 2015 @ 23:20
    jho
    2

    Calling controller action from partial view

    First time poster, long time reader :)

    I am trying to learn Umbraco MVC and I am stuck with a problem I cannot seem to work out. I want to create a page containing a table, with clickable table-headers. When clicking on a table-header, the table is sorted according to the header.

    My idea is to render the table in a partialview. The table header-links should be generated using Html.RenderActionLink, which reference an action in a SurfaceController (or RenderMvcController), that returns a sorted list of content.

    This is my setup:

    View

    @inherits UmbracoTemplatePage<DocumentType>
    
    ...code...
    
    @{ Html.RenderPartial("ListAllAssignments", TempData["viewModel"] ?? new AssignmentViewModel(Model)); }
    

    PartialView - ListAllAssignments.cshtml:

    @inherits UmbracoViewPage<AssignmentViewModel>
    
    <div>
       <table>
            <tr>
                <td>
                    @Html.ActionLink("[ID]", "SortBy", "AssignmentSurface", new { nodeId = Model.CurrentPage.Id, sortCategory = SortCategory.ID }, null)
                </td>
        </tr>
           table data here
        </table>
    </div>
    

    Controller:

    public class AssignmentSurfaceController : SurfaceController
    {
            [AcceptVerbs(HttpVerbs.Get)]
            public ActionResult SortBy(int nodeId, SortCategory sortCategory)
            {
                var overviewPage = DocumentTypeHelper.GetDocument<AssignmentOverviewPage>(nodeId);
                var assignmentViewModel = new AssignmentViewModel(overviewPage);
                var assignments = new AssignmentManager().GetAll();
    
                switch (sortCategory)
                {
                    case SortCategory.ID:
                        assignments = assignments.OrderBy(x => x.ID);
                        break;
                    default:
                        return null;
                }
    
                assignmentViewModel.AllAssignments = assignments.ToList();
                TempData["viewModel"] = assignmentViewModel;
    
                return RedirectToCurrentUmbracoPage();
            }
    }
    

    However, clicking the header in the table results in an error:

    Cannot find the Umbraco route definition in the route values, the request must be made in the context of an Umbraco request

    What am I doing wrong?

    Best regards

  • Alex Skrypnyk 6147 posts 24056 karma points MVP 8x admin c-trib
    Jan 11, 2015 @ 01:12
    Alex Skrypnyk
    0

    Hi jho ,

    You have to try define exactly url of request. Did you change something in routing ?

    Thanks

  • Cimplex 113 posts 576 karma points
    Jan 11, 2015 @ 01:33
    Cimplex
    101

    Hi jho, Whats happening here is that the surface controller dosent know what page you coming from and cant return "CurrentUmbracoPage" with the Html.ActionLink.

    I would solve this using a RenderMvcController and pass in the sorting category to it and from the controller return a custom RenderModel to get rid of your TempData fields.

    Create a RenderMvcController naming it: Document Type name = controller name Template name = action name and create a view model

    public class HomeController : Umbraco.Web.Mvc.RenderMvcController
    {
        public ActionResult HomePage(RenderModel model, int sort)
        {
            var viewModel = new HomePageViewModel(model.Content)
                                {
                                    Sort = sort
                                };
    
            return base.Index(viewModel);
        }
    }
    
    
    public class HomePageViewModel : RenderModel
    {
        public HomePageViewModel(IPublishedContent content)
            : base(content)
        {
        }
    
        public int Sort { get; set; }
    }
    

    Then you can use a Html.Action to render your partial. Like this:

    @Html.Action("SortBy","AssignmentSurface", new { nodeId = Model.Content.Id, sortCategory = Model.Sort })
    

    And finally in your Surface controller return the partialview:

    public class AssignmentSurfaceController : SurfaceController
    {
            [AcceptVerbs(HttpVerbs.Get)]
            public ActionResult SortBy(int nodeId, SortCategory sortCategory)
            {
                var overviewPage = DocumentTypeHelper.GetDocument<AssignmentOverviewPage>(nodeId);
                var assignmentViewModel = new AssignmentViewModel(overviewPage);
                var assignments = new AssignmentManager().GetAll();
    
                switch (sortCategory)
                {
                    case SortCategory.ID:
                        assignments = assignments.OrderBy(x => x.ID);
                        break;
                    default:
                        return null;
                }
    
                assignmentViewModel.AllAssignments = assignments.ToList();
                TempData["viewModel"] = assignmentViewModel;
    
                return PartialView("ListAllAssignments", assignmentViewModel);
            }
    }
    

    Your sorting urls would now look like this:

    <a href="@(Model.Content.Url + "?sort=" + 123)">Sort</a>
    

    Good luck!

  • jho 3 posts 35 karma points
    Jan 11, 2015 @ 13:26
    jho
    0

    Hi Cimplex

    Thank you for your suggestion! It almost works :)

    However, now I am recieving this exception:

    The parameters dictionary contains a null entry for parameter 'sort' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult AssignmentOverviewPage(Umbraco.Web.Models.RenderModel, Int32)' in 'AssignmentOverviewPageController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
    

    I did not change anything in the routing-table so far - but maybe I have to?

    This is my RenderMvcController:

    public class AssignmentOverviewPageController : RenderMvcController
    {
        public ActionResult AssignmentOverviewPage(RenderModel model, int sort)
        {
            var viewModel = new AssignmentViewModel(model.Content)
            {
                Sorting = sort
            };
            return base.Index(viewModel);
        }
    }
    

    This is the view of my RenderMvcController:

    @inherits UmbracoViewPage<AssignmentViewModel>
    <h2>AssignmentOverviewPage</h2>
    <div>    
        @Html.Action("SortBy", "AssignmentSurface", new { nodeId = Model.Content.Id, sortCategory = Model.Sorting });
    </div>
    
  • Cimplex 113 posts 576 karma points
    Jan 11, 2015 @ 13:33
    Cimplex
    0

    Hi jho,

    Try this:

    public ActionResult HomePage(RenderModel model, int? sort) {
    
    if(sort != null)
    // add value to your model like this (int)sort
    }
    else {
    // set the default sort value to the model
    }
    
    }
    

    The questionmark after the int will allow sort to be null.

  • jho 3 posts 35 karma points
    Jan 11, 2015 @ 13:47
    jho
    0

    Making sort nullable solved it.

    Thank you very much for the help - appreciated :)

    I'll mark your first post as the answer since that contains the majority of the changes I had to perform.

  • Willem Luijk 24 posts 95 karma points
    Sep 12, 2015 @ 00:30
    Willem Luijk
    0

    Dow anybody knows where i can find the DocumentTypeHelper from this example?

Please Sign in or register to post replies

Write your reply to:

Draft