Reputation: 437
I'm learning about ViewModels in C# ASP.NET MVC 3, and I'm stuck at displaying data from the ViewModel in my View.
The Models:
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class Book
{
public int Id { get; set; }
public int AuthorId { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
}
In my Index View I want to show general lists of both Authors and Books. I have made a ViewModel for this:
public class BookIndexViewModel
{
public List<Book> Books { get; set; }
public List<Author> Authors { get; set; }
}
Here is my Index() action method from the controller:
public ViewResult Index()
{
BookIndexViewModel viewModel = new BookIndexViewModel();
viewModel.Authors = db.Authors.ToList();
// leaving Books empty for now
return View(viewModel);
}
I have a strongly typed Index View where I want to show the list of Authors:
@model IEnumerable<NewBookStore.ViewModels.BookIndexViewModel>
@foreach (var author in Model.Authors) {
<tr>
<td>
@author.Name
</td>
</tr>
}
It's the Model.Authors part that doesn't work. When I type Model. and wait for IntelliSense to show Authors, it isn't listed. The error description is:
'System.Collections.Generic.IEnumerable' does not contain a definition for 'Authors' and no extension method 'Authors' accepting a first argument of type 'System.Collections.Generic.IEnumerable' could be found (are you missing a using directive or an assembly reference?)
Upvotes: 2
Views: 2863
Reputation: 61
[Note - I don't have enough exp to make this a comment rather than an answer!]
I was reading another article regarding ViewModels and from what @Darin Dimitrov was saying is that you should avoid putting Domain objects into your ViewModel,
"View models should not reference any services. View models should not reference any domain models."
see -> ASP.NET MVC 3 Viewmodel Pattern
I know patterns are more like guides that don't fit every scenario but like the OP, I need to display a list of domain objects (books and authors we'll just say) so in the OP's example, should the ViewModel have?:
public class BookIndexViewModel
{
public IEnumerable<SelectListItem> Books { get; set; }
public IEnumerable<SelectListItem> Authors { get; set; }
}
The BookIndexViewModel is then populated in your controller (which might use a service to get a list of Book and a list of Author to flatten into ViewModel) ??
I too am learning this stuff so open to suggestions/comments and corrections!! Thanks.
Upvotes: 0
Reputation: 136
Use this instead
@model NewBookStore.ViewModels.BookIndexViewModel
Upvotes: 0
Reputation: 876
the model in the view shouldnt be IEnumerable. You are sending a single model which has 2 lists in it. You are not sending a list of viewmodels.
Upvotes: 2
Reputation: 22485
Finnayra,
Your error here is that you aren't defining the model correctly. Your model already holds the IEnumerable<> collections, so no need to make it Enumerable as well. Try:
@model NewBookStore.ViewModels.BookIndexViewModel
Upvotes: 0
Reputation: 218722
Because you are not passing a collection
your View, You are passing only one object of BookIndexViewModel
class from your action method.
To fix this, update your view to to bind it to only one instance instead of a collection
@model NewBookStore.ViewModels.BookIndexViewModel
@foreach (var author in Model.Authors)
{
<tr>
<td>
@author.Name
</td>
</tr>
}
Upvotes: 0
Reputation: 4783
@model IEnumerable<NewBookStore.ViewModels.BookIndexViewModel>
should be
@model BookIndexViewModel
instead!
You don't want an IEnumerable
of BookIndexViewModel
- the Authors property is directly off your BookIndexViewModel
.
Cheers, Dean
Upvotes: 0