I want to post a List of items to controller from Razor view , but i am getting a List of objects as null My class structre is
Model:
List<Subjects> modelItem
class Subjects
{
int SubId{get;set;}
string Name{get;set;}
List<Students> StudentEntires{get;set;}
}
class StudentEntires
{
int StudId{get;set;}
string Name{get;set;}
int Mark{get;set;}
}
The model itself is a list of items and every items contain List of child items as well. Example model is a list of Subjects and every subject contains a List of Students, and i want to input mark for every student
My View is like
@model IList<Subjects>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
if (Model.Count > 0)
{
@for (int item = 0; item < Model.Count(); item++)
{
<b>@Model[item].Name</b><br />
@foreach (StudentEntires markItem in Model[item].StudentEntires)
{
@Html.TextBoxFor(modelItem => markItem.Mark)
}
}
<p style="text-align:center">
<input type="submit" class="btn btn-primary" value="Update" />
</p>
}
}
And in controller
[HttpPost]
public ActionResult OptionalMarks(int Id,ICollection<Subjects> model)
{
//BUt my model is null. Any idea about this?
}
Change the action method signature to
public ActionResult OptionalMarks(ICollection<Subjects> model)
Since in your HTML, it does not look like there is anything named
Id
in there. This isn't your main issue though.Next, do the following with the foor loop
Possibly due to the use of a
foreach
loop for theStudentEntries
, the model binder is having trouble piecing everything together, and thus a NULL is returned.EDIT:
Here's an example:
Controller
View
When you post the form, you should see the data come back in the
viewModel
object.You're finding this difficult because you're not utilising the full power of the MVC framework, so allow me to provide a working example.
First up, let's create a view model to encapsulate your view's data requirements:
Next, create a class to represent your subject model:
Finally, a class to represent a student:
At this point, you have all the classes you need to represent your data. Now let's create two controller actions, including some sample data so you can see how this works:
Now it's time to construct the views, and this part is particularly important when it comes to sending data back to a controller. First up is the
Index
view:You'll notice I'm simply using
Html.EditorFor
, whilst passingSubjects
as the parameter. The reason I'm doing this is because we're going to create anEditorTemplate
to represent aSubject
. I'll explain more later on. For now, just know thatEditorTemplates
andDisplayTemplates
are special folder names in MVC, so their names, and locations, are important.We're actually going to create two templates: one for
Subject
and one forStudent
. To do that, follow these steps:EditorTemplates
folder inside your view's current folder (e.g. if your view isHome\Index.cshtml
, create the folderHome\EditorTemplates
).Subject.cshtml
andStudent.cshtml
, respectively (again, the naming is important)).Subject.cshtml
should look like this:Student.cshtml
should look like this:That's it. If you now build and run this application, putting a breakpoint on the
POST
index action, you'll see the model is correctly populated.So, what are
EditorTemplates
, and their counterparts,DisplayTemplates
? They allow you to create reusable portions of views, allowing you to organise your views a little more.The great thing about them is the templated helpers, that is
Html.EditorFor
andHtml.DisplayFor
, are smart enough to know when they're dealing with a template for a collection. That means you no longer have to loop over the items, manually invoking a template each time. You also don't have to perform anynull
orCount()
checking, because the helpers will handle that all for you. You're left with views which are clean and free of logic.EditorTemplates
also generate appropriate names when you want to POST collections to a controller action. That makes model binding to a list much, much simpler than generating those names yourself. There are times where you'd still have to do that, but this is not one of them.