woggles
woggles

Reputation: 7444

MVC sorting with property on View Model

Say I have a view model for a list view that renders a table.

View Model:

  public class SortModel
  {
     public List<Document> Documents {get;set;}
     public string SortParameter {get;set;}
     public string SortOrder {get;set;}
  }

  public class Document
  {
     public string Name {get;set;}
     public int Age {get;set;}
  }     

View:

   <th>@Html.DisplayNameFor(model => model.Documents[0].Name)</th>
   <th>@Html.DisplayNameFor(model => model.Documents[0].Age)</th>

Controller:

public ActionResult Index(SortModel model)
{
   var docs = db.GetDocs();
   if(model.SortParameter == "Age" && model.SortOrder == "desc")
   {
      docs.OrderByDescending(x => x.Age);
   }  
   return View(model); 
}

How can I render the View so that the table headers are clickable and will update the model before posting? I want to avoid using ViewBag.

I'm guessing I'll need to use an ActionLink, but I'm not sure how to update the model before posting.

Something like:

<th>@Html.ActionLink("Index", "Home", "Name", new { Model.SortParameter = "Name", Model.SortOrder = "Desc"})

Upvotes: 1

Views: 2835

Answers (1)

user3559349
user3559349

Reputation:

Change you table headers to

<th>@Html.ActionLink("Name", "Index", "Home", new { SortParameter = "Name", SortOrder = Model.SortOrder }, null)</th>
<th>@Html.ActionLink("Name", "Index", "Home", new { SortParameter = "Age", SortOrder = Model.SortOrder }, null)</th>

and then modify the controller method to toggle the SortOrder

public ActionResult Index(SortModel model)
{
   var docs = db.GetDocs();
   if(model.SortParameter == "Age" && model.SortOrder == "desc")
   {
      docs.OrderByDescending(x => x.Age);
      model.SortOrder == "acs"
   }  
   return View(model); 
}

Note it would probably be easier if you had a bool IsAscending property rather than your string SortOrder.

However, you only have one 'SortOrder' property, so if the current view is displaying the Documents sorted by Name in ascending order, and the user clicks on Age, then the Documents will be sorted by Age in ascending order. If the user then clicks on Name, the Documents will be sorted by Name in descending order. You have not stated why the desired behavior is, but you could add multiple 'SortOrder' properties, say

public bool IsNameAscending { get; set; }
public bool IsAgeAscending { get; set; }

to handle that, and also to allow you to use a .ThenBy() in your query, for example

docs.OrderBy(x => x.Age).ThenBy(x=> x.Name);

You might also want to render a visual indicator (e.g. up or down arrows) to indicate the current sort order to the user.

Upvotes: 2

Related Questions