MVC 4 returns

So, I have a view that requires several different objects and lists of objects that need to be transferred and deleted, for which I created a viewmodel. My viewmodel looks like this

public class EditUserViewModel { public ManageUsersViewModel ManageUsersViewModel { get; set; } public IEnumerable<StateModel> StateModel { get; set; } } 

In the part I'm having problems with, there is a StateModel that looks like

 public class StateModel { public bool IsChecked { get; set; } public States States { get; set; } public UsersInStates UsersInStates { get; set; } } 

and contains it

 [Table("States")] public class States { [Key] public int StateId { get; set; } public string State { get; set; } } [Table("UsersInStates")] public class UsersInStates { [Key, Column(Order = 1)] public int UserId { get; set; } [Key, Column(Order = 2)] public int StateId { get; set; } public string LicenseNumber { get; set; } } 

In my opinion, I am more or less trying to iterate over states and enter user input for UsersInStates. This is how I try to do this, but my entire StateModel is returning null. Going to the StateModel.States view has data, but UsersInStates does not. This is what seems in my opinion

 @foreach (var state in Model.StateModel) { @Html.HiddenFor(m => state) <tr> <td> @Html.CheckBoxFor(m => state.IsChecked) </td> <td> @Html.Label(state.States.State) </td> <td> @Html.EditorFor(m => state.UsersInStates.LicenseNumber) </td> </tr> } 

Any advice would be highly appreciated. Everything displays as it should, and part of the ManageUsersViewModel works fine, but the StateModel data returning to the controller is zero, and I'm not quite sure how to make this work the way I would like.

Here is what the generated html looks like for the beginning of the table and the first row as requested

 <table style="margin-left:auto; margin-right:auto; text-align:center"> <input id="state" name="state" type="hidden" value="WebSiteNew.Models.StateModel" /> <tr> <td> <input data-val="true" data-val-required="The IsChecked field is required." id="state_IsChecked" name="state.IsChecked" type="checkbox" value="true" /> <input name="state.IsChecked" type="hidden" value="false" /> </td> <td> <label for="Alabama">Alabama</label> </td> <td> <input class="text-box single-line" id="state_UsersInStates_LicenseNumber" name="state.UsersInStates.LicenseNumber" type="text" value="" /> </td> </tr> 

Answer:

So, to solve this problem, I used a for loop as described in both of the links listed in the answer below

 @for (int i = 0; i < Model.StateModel.Count(); i++) { <tr> <td> @Html.HiddenFor(m => m.StateModel[i].States.StateId) @Html.HiddenFor(m => m.StateModel[i].States.State) @Html.CheckBoxFor(m => m.StateModel[i].IsChecked) </td> <td> @Html.Label(Model.StateModel[i].States.State) </td> <td> @Html.EditorFor(m => m.StateModel[i].UsersInStates.LicenseNumber) </td> </tr> } 

Also a note for anyone looking at this, I had to change the IEnumerable in my EditUsersViewModel to IList so that I could index.

+4
source share
2 answers

So your problem is that binding to the model does not work correctly.

Let's say you have two models:

 public class ParentModel { public string Name {get;set;} public ChildModel Child {get;set;} } public class ChildModel { public string ChildName {get;set;} public int SomeNumber {get;set;} } 

The generated HTML code (to properly bind your model) should look like this:

 <input name="Name" value="(Not relevant to this example)"/> <input name="Child.ChildName" value="(Not relevant to this example)" /> 

Notice how the name field is structured - this way MVC determines which input values ​​represent which properties in your view model. With a nested property, the name of the property must go before it.

With collections, it becomes more complex. The model’s middleware must know which values ​​go with which instance of the property.

For example, if we assume that ChildModel is of type IEnumerable in the previous example, your HTML might look something like this to model the binding correctly:

 <input name="Name" value="(Not relevant to this example)"/> <input name="Child[0].ChildName" value="(Not relevant to this example)" /> <input name="Child[0].SomeNumber" value="(Not relevant to this example)"/> <input name="Child[1].ChildName" value="(Not relevant to this example)" /> <input name="Child[1].SomeNumber" value="(Not relevant to this example)"/> 

Look at them how to fix it:

http://seesharpdeveloper.blogspot.com/2012/05/mvc-model-binding-to-list-of-complex.html http://haacked.com/archive/2008/10/23/model-binding-to -a-list.aspx

Change It is also important to note that when Html Helpers generate a name value, it is based on the passed lambda value. so

 @Html.CheckBoxFor(m => state.IsChecked) 

will generate the following name

 name="state.IsChecked" 

Since you are within foreach, you are getting the wrong value for the name.

+6
source

What are you trying to do with @Html.HiddenFor(m => state) - from the rendered HTML that looks like your culprit right there. Could @Html.HiddenFor(m => state.StateId) be more appropriate?

Alternatively, you can throw it into the first <td> element, as it is hidden and will preserve your HTML.

+1
source

Source: https://habr.com/ru/post/1480501/


All Articles