following on from an earlier post: Adding a search form using a DateTime template
I also tried following the Search example here: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
…but that doesn’t make use of a ViewModel as suggested in the answer to my previous post.
I am trying to help with a search from, which will take two dates (from/to), based on a ViewModel of:
public class SearchViewModel
{
[Required]
public DateTime From { get; set; }
[Required]
public DateTime To { get; set; }
}
My Views/Search/Index.cshtml is:
@model ttp.Models.SearchViewModel
@{
ViewBag.Title = "Search Availability";
}
<h2>Search Availability</h2>
@using (Html.BeginForm())
{
<div class="row">
<div class="span2">@Html.LabelFor(x => x.From)</div>
<div class="span2">@Html.EditorFor(x => x.From)</div>
<div class="span2">@Html.ValidationMessageFor(x => x.From)</div>
</div>
<div class="row">
<div class="span2">@Html.LabelFor(x => x.To)</div>
<div class="span2">@Html.EditorFor(x => x.To)</div>
<div class="span2">@Html.ValidationMessageFor(x => x.To)</div>
</div>
<div class="row">
<div class="span2 offset2"><button type="submit">Search</button></div>
</div>
}
The Get: /Search/Index controller is:
//
// GET: /Search/
public ActionResult Index()
{
SearchViewModel svm = new SearchViewModel();
svm.From = DateTime.Today;
svm.To = DateTime.Today;
return View(svm);
}
So far so good – my view shows the textboxes with the dates defaulting to today (using a DateTime Helper). When I click Search, the code goes to the SearchController // Post: / Search as follows:
//
// Post: /Search/
[HttpPost]
public ActionResult Index(SearchViewModel searchViewModel)
{
if (!ModelState.IsValid)
{
// Not valid, so just return the search boxes again
return View(searchViewModel);
}
// Get the From/To of the searchViewModel
DateTime dteFrom = searchViewModel.From;
DateTime dteto = searchViewModel.To;
// Query the database using the posted from/to dates
IQueryable<Room> rooms = db.Rooms.Where(r => r.Clients.Any(c => c.Departure >= dteFrom && c.Departure < dteTo));
// This is where I'm unsure
ViewBag.Rooms = rooms.ToList();
return View(rooms.ToList());
}
Where I’m at now unsure is the last couple of lines of the Post controller – how do I return the list of rooms in IQueryable rooms – and show the list of rooms on the screen? Do I redirect to another View (if so, how do I pass the list of rooms to that view)? If I just try and run the code above, I get the error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[ttp.Models.Room]', but this dictionary requires a model item of type 'ttp.Models.SearchViewModel'.
Am I trying to mix apples and pears – is there anyway of showing the list of rooms under the From and To search box (ViewModel)?
Thank you,
Mark
You could return a different view that will contain the search results:
And inside
Result.cshtml:If you want to stay no the same view, modify your view model so that it contains a third property which will represent the search results (a collection of rooms) that you will populate inside your POST controller action and redisplay the same view:
and then inside the view you could have a section to display the results:
But in both cases I guess that the
Roomobject is a domain model. Good practice dictates that you should define a view model in which you include only the information that your view needs:and then have an
IEnumerable<RoomViewModel> Rooms { get; set; }property to work with. You could still fetch yourIQueryable<Room>domain model in the controller action from your DAL layer, but before passing it to the view make sure to perform the conversion to the view model. It is where AutoMapper could come in handy.