Copied to clipboard

Flag this post as spam?

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


  • Dibs 175 posts 860 karma points
    6 days ago
    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 1283 posts 8694 karma points MVP 5x c-trib
    6 days ago
    Marc Goodson
    0

    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 search-result-type-@searchResult.DocTypeAlias.ToLower()">
                                    <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 175 posts 860 karma points
    2 days ago
    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'

Please Sign in or register to post replies

Write your reply to:

Draft