Reputation: 4231
I've read that it's generally a bad practice to use ViewBags and also bad to mix ViewBag and ViewModels, but I'm using some ViewBags to pass sort order
parameters between my controller and view and though I can create the properties on the ViewModel
for the view I need the values before I can create the model in the first place, so can't see how to get around this.
Controller
public ActionResult Index(string sortOrder, string searchString,
string currentFilter, int? page,
bool? includeComplete)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.NameSortParam = string.IsNullOrWhiteSpace(sortOrder) ? "Name desc" : "";
ViewBag.DateSortParam = sortOrder == "Date" ? "Date desc" : "Date";
if (Request.HttpMethod == "GET")
searchString = currentFilter;
else
page = 1;
ViewBag.CurrentFilter = searchString;
bool showCompleted = (includeComplete == null || includeComplete == false)
? false : true;
ViewBag.IncludeCompleted = showCompleted;
int pageNumber = (page ?? 1);
var query = Session.QueryOver<ToDo>();
if (!string.IsNullOrWhiteSpace(searchString))
query = query.WhereRestrictionOn(td => td.TaskName)
.IsInsensitiveLike(string.Format("%{0}%", searchString));
if (!showCompleted)
query.And(td => td.IsComplete == false);
switch (sortOrder)
{
case "Name desc":
query = query.OrderBy(td => td.TaskName).Desc;
break;
case "Date":
query = query.OrderBy(td => td.DueDate).Asc;
break;
case "Date desc":
query = query.OrderBy(td => td.DueDate).Desc;
break;
default:
query = query.OrderBy(td => td.TaskName).Asc;
break;
}
var result = query.Fetch(p=>p.Priority).Eager
.Fetch(s=>s.Staff).Eager
.List();
var viewModel = AutoMapper.Mapper.Map<IEnumerable<ToDo>,
IEnumerable<IndexToDoViewModel>>(result)
.ToPagedList(pageNumber, PageSize);
return View(viewModel);
}
Then in my view I'll use the ViewBag to pass values back to the controller, such as the sortOrder
which I need to have before I can apply it in my NHibernate
query that forms the bulk of the method, for example:
@Html.ActionLink("Name", "Index", new {sortOrder=ViewBag.NameSortParam,
includeComplete = ViewBag.IncludeCompleted})
My ViewModel
public class IndexToDoViewModel
{
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd MMM yyyy}")]
[DisplayName("Date Due")]
public DateTime? DueDate { get; set; }
public Guid Id { get; set; }
[DisplayName("Is Complete")]
public bool IsComplete { get; set; }
[DataType(DataType.MultilineText)]
public String Notes { get; set; }
public string Priority { get; set; }
public string Staff {get; set;}
[DisplayName("Name")]
public String TaskName { get; set; }
// These would potentially replace my ViewBag?
public string CurrentSort { get; set; }
public string CurrentFilter { get; set; }
public string NameSortParam { get; set; }
public string DateSortParam { get; set; }
public bool IncludeCompleted { get; set; }
}
Upvotes: 2
Views: 4329
Reputation: 700202
Then in my view I'll use the ViewBag to pass values back to the controller
No, you are passing the values to the next controller. The values will (potentially) be used after a round trip to the browser, when a new instance of the controller will handle the request.
As you are not passing anything back to the current controller, there is no need to use the ViewBag
. You can put the values in the model if you like.
Even if you were sending data from the view to the controller (which is very unusual), that would still be possible using the model. Example:
MyModel viewModel = new MyModel();
ActionResult result = View(viewModel);
// here you can access anything that the view would put in the model
return result;
Of course, you can't use any values from the view in the controller to create the model, as you have to create the model before the view. If you would need any data from the view to get data for it, you would put that as a method in the model instead of in the controller.
Upvotes: 3
Reputation: 9002
I would recommend creating a ViewModel for each of the views you create as it is most likely that further down the line you will need to pass more information to your view.
In this case, you would have a ViewModel that has a property for the paged list data and you can add another property for the SortOrder.
For example:
public class MyViewModel
{
public IEnumerable<ToDo> TodoList { get; set; }
public string SortOrder { get; set; }
}
See SO question: ViewModel Best Practices
Upvotes: 1