Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC 3 form post and persisting model data

I think I'm missing some fundamentals on how MVC forms work. I have a search form on my home page that has five or six different fields a user can search on. So I have this POSTing to my results action just fine. The Result action looks like this:

[HttpPost]
public ActionResult Results(SearchModel model)
{
    ResultsModel results = new ResultsModel();
    results.ResultList = SearchManager.Search(model).ToList();

    return View("Results", results);
}

I've simplified the above method for this post, but the idea is the same. So this all works fine. My results page shows up with the list of results and my user is at the following URL:

http://www.site.com/results

So...now I want to do something fairly common. I have two dropdown lists on the results page. "Sort by" and "# of results per page". How do I do that and send the full set of model data back to the controller so I can query with the new parameters? In reality, the SearchModel class has about 60 different fields. Potentially all of that data could be contained in the model. How do you persist that to a page "post back"?

This same question has me a little stumped about how to do paging as well. My paging links would go to a URL like:

http://www.site.com/results/2

But that assumes that we're responding to a GET request (I don't want 60 fields of data in the querystring) and that the model data is passed between GET requests, which I know isn't the case.

As I said, I think I'm missing some fundamentals about working with MVC 3, models and form posts.

Can anyone help point me in the right direction here? I'll be happy to edit/update this post as needed to clarify things.

EDIT: I also wanted to point out, I'd like to avoid storing the view model in a Session variable. This site will eventually end up being load balanced in a web farm and I'm really trying to avoid using Session if possible. However, if it's the only alternative, I'll configure another session state provider, but I'd prefer not to.

like image 647
Scott Avatar asked May 01 '11 15:05

Scott


2 Answers

You can add your current SearchModel parameters to the route values for your form. Several versions of BeginForm allow you to pass in an object/RouteValuesDictionary.

@Html.BeginForm("Action", "Controller", new { SearchModel = Model }, FormMethod.Post)

This should pass-through your current SearchModel values so you can re-use them to get the next page. You need to have a controller action defined that will accept any current-page form values as well as the SearchModel.

I have not done this with form posts, but from what I have done and from what the docs say, this is where I would start. Of course, this also means that each of your page number "links" on the page will need to be doing posts. That is really inconvenient for users if they want to be able to use the Back button in the browser.

In this context, you can try to define a route that allows the page number to appear as a part of the URL -- "Action/Controller/{page}". However, I am not sure how that will work given that the form is doing a post.

Response to Comment:

Yeah, you can use Route Values to add the SearchModel to each page link, but as I said in the comment above, since the links will do a "get," your users will see the SearchModel serialized as a part of the link.

Either way, using Route Values is your answer to getting back your original SearchModel without using hidden fields, Session, or TempData.

like image 188
BJ Safdie Avatar answered Nov 07 '22 09:11

BJ Safdie


Your SearchModel class needs to contain your search criteria and your results. Something like below. If you use a PagedList for your results then it will contain the current page, total pages, total items, etc. You can limit the amount of information in your page by only writing the search criteria that contain values.

public class SearchModel
{
    public string Product { get; set; }
    public string Sku { get; set; }
    public string Size { get; set; }
    public string Manufacturer { get; set; }
    // etc...

    public PagedList ResultsList { get; set; }
}


[HttpPost]
public ActionResult Results(SearchModel model)
{
    model.ResultList = SearchManager.Search(model).ToList();
    return View(model);
}
like image 8
37Stars Avatar answered Nov 07 '22 07:11

37Stars