views:

211

answers:

1

Hi guys. I am fairly new to MVC. I am trying to set up a search page that searches a database and returns results. The search box is within a Html.BeginForm in my View, and looks like this:

   <% using (Html.BeginForm())
     { %>
      <%= Html.TextBox("searchBox", null, new { @id = "searchBox" })%>
       <div id="searchButtonsDiv">
        <input type="submit" value="Search" />
      </div>
  <% } %>

  //Results are returned in a ul and orgainized


   //Pagination below
   <% if (Model.HasPreviousPage)
      { %>
        <%= Html.RouteLink("Previous", "SearchResults", new { page = (Model.PageIndex - 1) })%>
   <% } %>
   <% if (Model.HasNextPage)
      {  %>
         <%= Html.RouteLink("Next", "SearchResults", new { formCollection = "", page = (Model.PageIndex + 1) })%>
   <% } %>

I am using a FormCollection to pass to my controller that looks like this:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Index(FormCollection formCollection, int? page)
    {
        var searchString = formCollection["searchBox"]; 
        var results = resultsRepository.GetResults();

        var paginatedResults = new PaginatedList<Driver>(results, page ?? 0, pageSize);

        return View(paginatedResults);
    }

So far so good. When I type a word and press the submit button, Index gets called and the database returns accordingly. The ul gets populated with the results, and when there are more than pageSize results (10 in my case), the Next link shows up.

When I click "Next", the default page just loads. No pagination or anything like that. I'm pretty sure it has to do with the fact that my Index ActionResult has a FormCollection as a paramater. I thought I read somewhere that only strings/ints can be handled? Here is the MapRoute:

        routes.MapRoute(
            "SearchResults",
            "Drivers/Index/{formCollection}/{page}",
            new { controller = "Drivers", action = "Index", formCollection = "", page = "" }
        );

Am I completely missing something or is there a way to handle this? I know I could just use jquery/ajax to send the string contained in the search listbox, but I don't want to do that because later I plan on adding checkbox's as means of filtering searches, etc.

I tried several different ways of setting the formCollection's value, including creating a new FormCollection that adds the searchBox, and just passing strings, etc.

+1  A: 

The FormCollection argument in the action isn't the problem. That will always work.

It absolutely does not belong in your route, however! Just get rid of that and you'll probably solve the problem. Form elements don't go in the URI, and only stuff in the URI should be in the route.

It's not how I'd write that action signature, however. I'd suggest:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(string searchBox, int? page)
{
    var results = resultsRepository.GetResults();

    var paginatedResults = new PaginatedList<Driver>(results, page ?? 0, pageSize);

    return View(paginatedResults);
}

Finally: You shouldn't return a View from a POST in this case. This will cause weird behavior for the user; e.g., when they press refresh their browser will warn them about re-submitting the form.

You should either:

  1. Use a GET, not a POST for search results.
  2. Redirect instead of returning a view.

I'd pick the first, personally.

Craig Stuntz
Well I have to use POST since the Index action is overloaded (the first returning a view and the second returning the same view but paginated with the search results).When you say remove it from the route, do you mean so it will look like this?: routes.MapRoute( "SearchResults", "Drivers/Index/{page}", new { controller = "Drivers", action = "Index", page = "" } );When I do this, the ActionResult Index() gets called instead. (I have it above all other routes just in case)
Darcy
`GET` v. `POST` has *far reaching* consequences and *should not* be used for overload resolution! You need only one action here anyway -- when `searchBox` is null/empty and `page` has no value, return the un-paginated results. If `Index` isn't called when you fix your routing, then you have other problems not mentioned here. `FormCollection` should **never** be in a route, ever!
Craig Stuntz