10

I am using ASP.NET MVC 4 with entity framework model first.

In my "Masterpage.cshtml" I want to have a partial view which contains a textbox and a button.

The search is looking for the items title, if the text contains a items title it should display those items.

When a text is submitted the @renderbody() should show a view with the items.

My question is how can I do this in a good way? whats a good and easy approach?

So far I have done this:

Created a method in my repository that does the search function:

public List<News> Search(string query)
        {

            var queryz =  db.News.Where(x => x.Title.Contains(query));
            return queryz.ToList();
        }

Now when it comes to my Searchcontroller im kinda lost how to do this. Beacuse one actionresult need to be the partialview that has a string query parameter and other one that contains a view that will display the items?

What I have done right now is having the whole process in same actionresult:

 Repository rep = new Repository();
        [HttpPost]
        public ActionResult Search(string query)
        {
            var searchlist = rep.Search(query);

            var model = new ItemViewModel()
            {
                NewsList = new List<NewsViewModel>()
            };

            foreach (var NewsItems in searchlist)
            {
                FillProductToModel(model, NewsItems);
            }

            return View(model);
        }

        private void FillProductToModel(ItemViewModel model, News news)
        {
            var productViewModel = new NewsViewModel
            {

                Description = news.Description,
                NewsId = news.Id,
                Title = news.Title,
                link = news.Link,
                Imageurl = news.Image,
                PubDate = news.Date,
            };
            model.NewsList.Add(productViewModel);
        }

any kind of help is appreciated alot!

Obsivus
  • 8,231
  • 13
  • 52
  • 97

2 Answers2

26

You could use the following approach:

Index.cshtml

Have one DIV that calls the search controller action, and another that'll display the results.

<div id="search-form">
    @Html.Action("Search", "Home");  // GET action in controller that displays form
</div>
<div id="search-results">
</div>

_SearchFormPartial.cshtml

Create a partial view that'll contain the search form. You can use Ajax.BeginForm so when a user searches the results will be displayed in the search-results DIV in Index.cshtml by AJAX. UpdateTargetId specifies that we want to pass the results of the search to the search-results DIV.

@using (Ajax.BeginForm("Search", "Home", FormMethod.Post,
        new AjaxOptions
        {
            InsertionMode = InsertionMode.Replace,
            HttpMethod = "POST",
            UpdateTargetId = "search-results"
         }))
{
<div>
    @Html.TextBox("query")
    <input type="submit" value="Search" />
</div>      
}

Controller

In your controller you'll need one action to display the form (partial view above) and another to process the search query and retun another partial view that'll display the results:

[HttpGet]
public ActionResult Search()
{
    return PartialView("_SearchFormPartial");
}

[HttpPost]
public ActionResult Search(string query)
{
    if(query != null)
    {
        try
        {
            var searchlist = rep.Search(query);

            var model = new ItemViewModel()
            {
                NewsList = new List<NewsViewModel>()
            };

            return PartialView("_SearchResultsPartial", model);
        }
        catch (Exception e)
        {
            // handle exception
        }
    }
    return PartialView("Error");
}

_SearchResultsPartial.cshtml

This partial will display the results. It's strongly typed taking in an ItemViewModel.

@model Namespace.ViewModels.ItemViewModel
@if (Model.SearchResults.Count == 0)
{
    <h3 class="text-error">No items matched your search query!</h3>
}
else
{
    foreach (var result in Model.NewsList)
    {
        // display search results
    }
}
Harry
  • 61
  • 1
  • 15
MattSull
  • 5,514
  • 5
  • 46
  • 68
  • there is no textbox in the search form, should I add a string property in my viewmodel and add a textbox?? or? – Obsivus May 19 '13 at 20:53
  • Sorry, forgot about that, see edit. Is there a number of search fields or just one? – MattSull May 19 '13 at 20:55
  • just one textbox, but will the textbox value be the string parameter inside the actionresults? or do i need to do something? – Obsivus May 19 '13 at 20:56
  • See edit. The string value in `TextBox` should match what's being passed into the controller action. – MattSull May 19 '13 at 21:07
  • Hmm is it possible to make sure that when the form is submitted they get to a view with the search result div inside? – Obsivus May 19 '13 at 21:20
  • Yes, move the `search-results` DIV to the view that you want to display the results. You'll also have to change the return of the POST action, something like: `return View ("SomeView", model);`. Also if you're redirecting to another view you could just use a `Html.BeginForm` – MattSull May 19 '13 at 21:23
  • I applied everything but it seems that everything runs infinitly I get nsufficient stack to continue executing the program safely. This can happen from having too many functions on the call stack or function on the stack using too much stack space. this error on the htmlhelper action – Obsivus May 20 '13 at 20:59
  • May have something to do with the controller actions having the same name. Try changing the GET action to something like DisplaySearchForm and update `Html.Action()`. – MattSull May 20 '13 at 22:37
  • Yeah I fixed it :) Btw will this search functionality perform well when it comes to many users using it? the web app will be used for over 300 000 users same time – Obsivus May 20 '13 at 22:48
  • Great stuff. You should open a new question asking specifically that. Show the search method, mention expected traffic etc. Don't forget, if you found the answer helpful, you can always up-vote. – MattSull May 20 '13 at 22:54
  • Great explanation and sample code. This was really helpful to me with a current project. – PixelPaul Mar 07 '17 at 12:56
  • Can you please explain the `SearchResults` of `ItemViewModel` in `_SearchResultsPartial.cshtml` ? – Ahmed Aug 24 '22 at 07:40
0

If your _SearchResultsPartial.cshtml is not inserted into the DOM element of given ID, you should add a script: query.unobtrusive-ajax.js

It fixed the MattSull's solution in my case