Copied to clipboard

Flag this post as spam?

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


  • Anthony 3 posts 73 karma points
    Feb 09, 2021 @ 13:48
    Anthony
    0

    Does CurrentUmbracoPage keep the view model?

    I am trying to implement a simple search page but when I return from the HttpPost action the Model is null.

    The search form is implemented as partial views and called from the template page by Html.Action.

    When I post to the controller and return CurrentUmbracoPage:

    [HttpPost]
    public ActionResult HandleSearchForm(SearchViewModel vm)
    {
         vm.Message = "Ta da! " + vm.SearchText;
         return CurrentUmbracoPage();
    }
    

    The view renders the message:

    @vm.Message
    

    Alas, the message is always NULL.

    I'm trying to figure out if the MODEL is even used in this scenario or whether CurrentUmbracoPage just deals with data in the ModelState, ViewData etc.

    What would be the pattern to use in this case: search > post > display results

    Help greatly appreciated.

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Feb 21, 2021 @ 11:07
    Marc Goodson
    1

    Hi Anthony

    Yes, it can feel a little bit weird, because Umbraco itself uses a default MVC Controller (RenderMvcController) implementation to render all incoming requests to Umbraco for content.

    The SurfaceController is designed to umm sit on the 'Surface' of this interaction. It does not interact directly with the ViewModel of the content page when it is rendered, which is why your setting of the property isn't working.

    It can interact with 'ModelState' as it needs to check if the form data being posted is valid, so you can manipuate the ModelState if needs be to return error messages, and returning CurrentUmbracoPage, effectively runs the RenderMvcController again, but with the ModelState for your form intact - to show the error messages.

    You can therefore add custom messages from a SurfaceController handling a form postback by using TempData or the ViewBag (https://rachelappel.com/2014/01/02/when-to-use-viewbag-viewdata-or-tempdata-in-asp-net-mvc-3-applications/)

    TempData["successMessage"] = "Yey it worked";
    

    So think of the SurfaceController really as only handling a postback, and determining whether the posted values are valid or not, if they are not valid it returns the CurrentUmbracoPage and displays error messages, but if all is ok - then depending what the form is intended to do, you might send an email, log entries to a db table, etc, and then redirect to another page, or back to the current page clearing modelstate by return RedirectToCurrentUmbracoPage (there is a full list of options here: https://our.umbraco.com/documentation/reference/routing/surface-controllers-actions)

    So how does that help you display search results?

    (It doesnt'!)

    The pattern would be once your SurfaceController has handled the form post and made sure it's a valid request - would be to 'redirect' with the search parameters on a querystring to a GET route that actually performs the search and can render the view containing the results.

    The common way to do this with Umbraco is to create a hijacked RenderMvcController:

    https://our.umbraco.com/Documentation/Reference/Routing/custom-controllers

    If you create a SearchResults Document Type in Umbraco then any request to a page based on that DocumentType will be routed via your Custom MVC Controller IF it matches the alias of the DocumentType and inherits from RenderMvcController class:

    public class SearchResultsController : Umbraco.Web.Mvc.RenderMvcController
    {
        public ActionResult Index(ContentModel model, string searchTerm="")
        {
            // you are in control here!
            // if you create your own ViewModel that inherits from ContentModel, 
              you can set it's custom properties here:
             var viewModel = new SearchResultsViewModel(model);
             //do the search!
             viewModel.SearchTerm = searchTerm;
    
             viewModel.SearchResults = _mySuperSearchService(searchTerm);
            // return the 'model' to the selected template/view for this page.
            return CurrentTemplate(viewModel);
        }
    }
    

    You'll need to update your template view to inherit from your custom view model

    @inherits UmbracoViewPage<SearchResultsViewModel>
    

    But then you'll be able to use the properties on your model in your view

    eg

    @if (Model.HasSearchResults){
    <h2>Search Results</h2>
    @foreach (var result in Model.SearchResults){
    <li>@result.Name</li>
    }    
    

    }

    So yeah, it's a little bit convoluted, but if you think SurfaceController just handles the form post, and custom RenderMvcController is responsible for displaying things, then it sort of isn't so bad as a pattern once you've got it working once.

    regards

    marc

  • Anthony 3 posts 73 karma points
    Feb 21, 2021 @ 11:17
    Anthony
    0

    I just want to thank you for taking the time out to explain this! Thanks!

Please Sign in or register to post replies

Write your reply to:

Draft