Iterate for each item in IEnumerable - c#

I think I am missing something simple here.
In my controller I have
public ActionResult ListPage()
{
return View(db.Sections.OrderBy(x=>x.Order).ToList());
}
On the ListPage.cshtml I have
#model IEnumerable<Section>
#foreach (var item in Model)
{
#Html.DisplayFor(item => item, "SectionTemplate")
}
And in the Views/Shared/DisplayTemplates/SectionTemplate.cshtml I'm not sure what to put. Ideally this view would look like
#model Section
<h1>#Model.Title</h1>
But a little more robust obviously.
When I do that, I get an error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Section]', but this dictionary requires a model item of type 'Section'.
How can I change this code to access the properties on the individual model in the template?
Thanks!

In your code, inside of the lambda, item resolves to the parameter of said lambda, and not the item declared in the outer scope. Just rename the parameter of your lambda and it should work as expected:
#foreach (var item in Model)
{
#Html.DisplayFor(_ => item, "SectionTemplate")
}

Related

Change from List to IEnumerable

My application stops and give me this error message:
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[Test.Models.GamesVM]',
but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1
[Test.Models.Runner]'.
My Controller:
return PartialView("PartialViewAllRunners", db.Runners.ToList());
My View:
#Html.Partial("~/Views/Shared/PartialViewAllRunners.cshtml", Model)
Both View and the Partial View has IEnumerable, so what is the problem and what needs to be changed?
Edit - Change your view model to this:
#model IEnumerable < ModelClass Name>
return View(db.modelclass.ToList());

Passing list to view in asp.net mvc

Here is my action method from controller.
public class MoviesController : Controller
{
private MovieDBContext db = new MovieDBContext();
// GET: /Movies/
public ActionResult Index()
{
return View( db.Movies.ToList() );
}
}
As it can be seen a List is being passed to View that is why I am expecting to work with it as Listin view but in View it works as IEnumerable
Following is the first line from View
#model IEnumerable<MVCWebApplication2.Models.Movie>
Why passed value that was List behaves as IEnumerable?
Is IEnumerable super class of List?
List<T> implements the IEnumerable<T> interface:
http://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx
It is typically a best practice to try to work with interfaces where possible to keep your code decoupled, so that's why the View was scaffolded like that. In this instance, you could pass any other Movie collection that implements IEnumerable<T> to your View, and your View would happily render without issue.
So, imagine you have another Action in some other Controller like:
public ActionResult Index()
{
Queue<Movie> movies = new Queue<Movie>();
movies.Enqueue(db.Movies.Single(m => m.Title == "Flash Gordon"));
movies.Enqueue(db.Movies.Single(m => m.Title == "Star Wars"));
return View( "Movie/Index", movies );
}
Because Queue<T> implements IEnumberable<T>, movies will get rendered by the same View without having to make any changes to it. If your View was typed to List<Movies>, you would need to create a whole separate View to accommodate your Queue<Movies> model!
As Chris mentioned, List<T> implements IEnumerable<T>, so that is why it is valid for the View's model to be:
#model IEnumerable<MVCWebApplication2.Models.Movie>
Since you said you want to use it as a List, the List also implements IList<T> which should provide you with the functionality you were expecting to have in your view.
You can make use of the List methods like so:
#model IList<MVCWebApplication2.Models.Movie>
<div>
First movie: #Model.First().Name
</div>
#Model.Count Action Movies:
<ul>
#foreach (var item in Model.Where(x => x.Type = "ActionMovie"))
{
<li>#item.Name - #item.Description</li>
}
</ul>

The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[System.String]' but requires type "Something else"

I am using the following codes..
Controller:
public ActionResult Comments(int? Id)
{
var abccomment= db.xyzComments.Include(c=>c.XYZMasters);
var comments = (from x in abccomment
where Id == x.CcId
select x.Comment).Distinct().ToList();
return View(comments);
}
and my view is
#model IEnumerable<Pharman.Models.XYZMaster>
#foreach (var item in Model)
{
#item.XYZComment.Comment
}
I get the following error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[System.String]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[farma.Models.XYZMaster].
pls help... TIA
Type of your ViewModel is IEnumerable<Pharman.Models.XYZMaster> but you are passing List<string>
You should change your ViewModel type to IEnumerable<string>
Then:
#model IEnumerable<string>
#foreach (var comment in Model)
{
#comment
}

Can I have a named display template for a collection

I have a display for a collection of "SomeObject"
public List<SomeObject> SomeObjects
#Html.DisplayFor(m => m.SomeObjects)
This all works fine.. Then I had a requirement that meant I would need a second different display template for the same collection..
#Html.DisplayFor(m => m.SomeObjects, "NameOfTemplate")
I get the below message when I do this.. I have used named display templates before, but maybe it only works for primitive types - strings etc?
'System.Collections.Generic.List1[SomeObject]', but this dictionary
requires a model item of type 'SomeObject'.
Adding code as request
"Test" DisplayTemplate
#model ViewModels.SomeObject
<p class="Namme">
<span>#Model.Name</span>
</p>
SimpleViewModel
public class SomeObject
{
public string Name { get; set; }
}
Property in ParentViewModel
public List<SomeObject> SomeObjects { get; set; }
Cshtml file..
#Html.DisplayFor(m => m.SomeObjects, "Test")
To me its a simple question, can a named template be used with a collection or not? Is it another limitation of mvc..
Cheers,
John
Yes you are passing a list of SomeObject to your display template, when it is expecting:
#model ViewModels.SomeObject
You either need to change the template to something like this and accept a list as the view model:
#model IList<ViewModels.SomeObject>
#foreach (var item in Model) {
<p class="Namme">
<span>#item</span>
</p>
}
Or change what you are passing into the Display Template in the parent CSHTML file and make it a single object of SomeObject something like this:
public List<SomeObject> SomeObjects
#foreach (var item in Model.SomeObjects) {
Html.DisplayFor(item, "TemplateName")
}
Its hard to answer because im not sure what your trying to achieve, and what SomeObject is, but this should point you in the right direction.
The type of SomObjects is List<SomeObjects> so the view template must have a matching model:
#model `ICollection<ViewModels.SomeObject>`
I prefer to not restrict the view to the concrete List<> class but rather use an interface.
That also means that you have to adjust your template to use a loop to iterate through the items in the collection.

Razor Dynamic Models Breaking

I created a C# Razor site with no explicit model definitions, relying on the dynamic keyword to represent my model. However, this is now breaking because it says that "object doesn't contain member X". It does contain it; intellisense shows this, but whatever is using the model, when dynamic, is breaking. Even adding #model dynamic doesn't work.
Changing to an explicit model is working, so I'm doing that, but what would cause dynamic support to stop working in process?
EDIT:
My controller simply does this:
public ActionResult List()
{
return View(new
{
Data = repos.GetData()
});
}
and the uses it directly:
#{ Title = "X" }
#foreach (var item in Model.Data)
{
Render
}
The model and data is not null, and there is valid data.
Thanks.
If you want to utilize dynamic types to be passed, you should use the ViewBag property. Your code could read:
public ActionResult List()
{
ViewBag.Data = repos.GetData();
return View();
}
Your View:
#foreach (var item in ViewBag.Data)
{
Render
}
I tried to get your code working but I also throw the same error.
try this:
Model:
public ActionResult List()
{
dynamic returnModel = new ExpandoObject();
returnModel.Data = repos.GetData();
return View(returnModel);
}
View:
#{
ViewBag.Title = "title";
}
#foreach (var item in Model.Data)
{
// html for item
}

Categories