Copied to clipboard

Flag this post as spam?

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


  • Dibs 202 posts 991 karma points
    Oct 16, 2020 @ 11:39
    Dibs
    0

    moving search functionality code to controller

    Hi Umbraco Team

    I am trying to move code from view to controller, learning how to make use of MVC in Umbraco. My goal is to create a partial view for the search box and submit button and a search results page that displays search results. Sounds simple, but to the life of me i cant get it to work via SufaceController or RenderMvcController. I keep getting errors in my code.

    I have the partial search term form, this i would like to render on header and search results page.

    @inherits Umbraco.Web.Mvc.UmbracoViewPage
    @using (Html.BeginUmbracoForm("Finder", "Find", FormMethod.Post))
    {
        <input type="text" placeholder="Search" id="query" name="query" />
    
        <input type="submit" name="Submit" value="Submit" />
    }
    

    This works fine : ) This is my Controller, named after my DocType in backoffice

    using System;
    using System.Web.Mvc;
    using Umbraco.Web.Models;
    using Umbraco.Web.Mvc;
    
    namespace ScottishPrenier.Core.Controllers
    {
        public class FindController : SurfaceController
        {
            public ActionResult Finder(ContentModel model, string query)
            {
                var searchTerm = string.Empty;
                searchTerm = string.IsNullOrWhiteSpace(query) ? String.Empty : query;
    
                if (searchTerm == String.Empty)
                {
                    ViewBag.q = "Enter search Term";
                    return CurrentUmbracoPage();
                }
    
                ViewBag.q = searchTerm;
                return CurrentUmbracoPage();
            }
    
    
            public ActionResult Form(ContentModel model)
            {
                return PartialView("Finder Partial View", model);
            }
    
        }
    }
    

    This is my search results page, find.cshtml

    @inherits Umbraco.Web.Mvc.UmbracoViewPage
    @{
        Layout = "master.cshtml";
    }
    @* the fun starts here *@
    @{ Html.RenderAction("Form", "Find", new { model = Model, query = Request.QueryString["query"] }); }
    

    The above code is a starting block for me to get the search results page rendering via direct access or via the search term form. The above code works as expected, search results page renders ok.

    My next step is to make use of a custom model to hold title link and excerpt of search results from the search term and render them on the search results page.

    My custom model is

    using System.Collections.Generic;
    using Umbraco.Core.Models.PublishedContent;
    using Umbraco.Web.Models;
    
    namespace ScottishPrenier.Core.Models
    {
        public class SearchResult : ContentModel
        {
            public SearchResult(IPublishedContent content) : base(content)
            {
    
            }
            public string Title { get; set; }
            public string Excerpt { get; set; }
            public string Link { get; set; }
            public IEnumerable<IPublishedContent> SearchResults { get; set; }
    
        }
    }
    

    Here is where i get stuck, i make a change to my search results page Find.cshtml to inherit my custom model.

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<SearchResults>
    

    This causes following error

    Cannot bind source type Umbraco.Web.Models.ContentModel to model type SearchResult.
    

    passing the custom model to the controller makes no difference. Changing my controller to use RenderMvcController causes The name 'CurrentUmbracoPage' does not exist in the current context.

    Im not sure how i can make my custom model fit in my current code to display search results on my search results page

    Anybody able to assist or advise where im going wrong ?

    Thanks Dibs

  • Marc Goodson 2141 posts 14324 karma points MVP 8x c-trib
    Oct 16, 2020 @ 20:08
    Marc Goodson
    102

    Hi Dibs

    There are different ways of making this work.

    Generally the rule of thumb for Umbraco is to use a SurfaceController that has the job of handling a 'post back' from a form - and also for convenient ChildActions for rendering a PartialView inside your Umbraco template, eg to present the form.

    However, you would typically use a RenderMvcController to handle the rendering of content for a request.

    Therefore in this kind of pattern you often end up with two Controllers, one a SurfaceController that has a child action that Renders the form, and an Action that handles the postback from the form - checks validation etc

    but if the form posting back validates then the SurfaceController would usually redirect to a GetRequest to a RenderMvcController that has the job of performing the search, and passing a custom model to the view to display the results.

    So if your Search Results Page has Document Type 'SearchPage'

    Create a controller called 'SearchPageController' that inherits from RenderMvcController

          public class SearchPageController : RenderMvcController
            {
                public ActionResult Index(ContentModel model, string searchTerm = "", int page = 1)
                {
                    //create your custom view model
                    SearchPageViewModel searchPageViewModel = new SearchPageViewModel(model.Content, model.CurrentCulture));
        //do the search
                    searchPageViewModel.SearchResults = SiteSearchService.SearchSite(searchTerm, page);
         then return the custom model:
                    return CurrentTemplate(searchPageViewModel);
                }
    }
    

    Then your view can inherit this custom model

    @inherits UmbracoViewPage<SearchPageViewModel>
    

    You can render your search form either directly from a partial:

    <div>
    @Html.Partial("SearchForm", new SiteSearchCriteria() { SearchTerm = Model.SearchResults.SearchTerm })
    </div>
    

    or via a child action @Html.Action("RenderSearchForm","SearchFormSurface")

    and have a property on your custom model determining if there are search results

      @if (Model.SearchResults.HasSearchResults)
                    {
      <ol class="list-group list-group__minimal">
                            @foreach (var searchResult in Model.SearchResults.Results)
                            {
                                <li class="list-group-item [email protected]()">
                                    <a href="@searchResult.Url" class="h5">@searchResult.Title</a>
                                    @if (!string.IsNullOrEmpty(searchResult.Summary))
                                    {
                                        <p>@searchResult.Summary</p>
                                    }
                                </li>
                            }
                        </ol>
    
    }
    

    And then your SurfaceController could look something like this:

    public class SearchController : SurfaceController
    {
        [HttpPost]
        public ActionResult Search(SiteSearchCriteria searchCriteria)
        {
            if (!ModelState.IsValid)
            {
                return CurrentUmbracoPage();
            }
            else
            {
                var searchResultsPage = SiteService.GetSearchPage();
                return RedirectToUmbracoPage(searchResultsPage,"searchTerm=" + searchCriteria.SearchTerm);
            }
        }
    }
    

    so basically all it does is validate the posting of the form, and then redirect to the searchpage to enable the RenderMvcController to do the searching...

    So I think you have most of the bits there, but not handling the request to the search page... but there are lots of different ways of doing this!

    regards

    Marc

  • Dibs 202 posts 991 karma points
    Oct 20, 2020 @ 08:22
    Dibs
    1

    Hi Marc thanks for reply

    I get the gist of what your saying, i'll give it a go : )

    Dibs P.S as Arnie would say 'i'll be back'

  • Dibs 202 posts 991 karma points
    Oct 26, 2020 @ 15:06
    Dibs
    1

    Cheers Marc

    Got the gist and got it working following your code example, SurfaceController to render and post form. SufaceController action to redirect to RenderMvcController with searchTerm via RedirectToUmbracoPage(pageID, requestString)

    RenderMvcController to do the number crunching and send results to view page.

    Dibs : )

  • Marc Goodson 2141 posts 14324 karma points MVP 8x c-trib
    Oct 26, 2020 @ 17:32
    Marc Goodson
    1

    Great Dibs! - can't think of an appropriate Arnie line from a film...

    ... but apparently he does inspirational quotes too:

    "Strength does not come from winning. Your struggles develop your strengths. When you go through hardships and decide not to surrender, that is strength"

    not as snappy as

    "consider that a divorce"

    though :-P

    regards

    Marc

Please Sign in or register to post replies

Write your reply to:

Draft