LabelFor does not work in a loop (for / foreach / template)

I am trying to create a list of checkboxes, but Html.LabelFor is not working. It continues to generate <label for="">Some text</label> , note the empty For attribute.

I tried the for and foreach loop before trying to use the display pattern, but all of these have problems. I refuse to believe that writing input fields manually is the only solution. All tips / advice are greatly appreciated.

Model:

 public class MyViewModel { public string Name { get; set; } public bool Selected { get; set; } } 

Controller:

 public ActionResult MyController() { var model = new List<MyViewModel>(); model.Add(new MyViewModel() { Name= "Foo" }); model.Add(new MyViewModel() { Name= "Bar" }); return View(model); } 

View:

 @model IEnumerable<MyViewModel> <div> @Html.DisplayFor(x => Model) </div> 

Display Template:

 @model MyViewModel <p> @Html.LabelFor(model => model.Selected, Model.Name) @Html.EditorFor(model => model.Selected) </p> 

Result:

 <div> <p> <label for="">Foo</label> <input class="check-box" data-val="true" data-val-required="The Foo field is required." name="[0].Selected" type="checkbox" value="true" /> <input name="[0].Selected" type="hidden" value="false" /> </p> <p> <label for="">Bar</label> <input class="check-box" data-val="true" data-val-required="The Bar field is required." name="[1].Selected" type="checkbox" value="true" /> <input name="[1].Selected" type="hidden" value="false" /> </p> <div> 

As you can see, <label> does not work as intended.

+4
source share
4 answers

The fact is, since in your main view you have IEnumerable<MyViewModel> , the prefix is [0].Selected , which the helpers do not like. You will also notice that your flag does not have an identifier. Here's a hack that you can use to change this prefix:

 @model MyViewModel @{ ViewData.TemplateInfo.HtmlFieldPrefix = "Model" + ViewData.TemplateInfo.HtmlFieldPrefix; } <p> @Html.LabelFor(model => model.Selected, Model.Name) @Html.EditorFor(model => model.Selected) </p> 

Obviously, this assumes your POST action argument is called model :

 [HttpPost] public ActionResult Index(IEnumerable<MyViewModel> model) { ... } 

which may not always be so.

Also note that instead of @Html.DisplayFor(x => Model) in the main view, you can use @Html.EditorForModel() .

Another possibility is to wrap this in a view model with the collection property:

public class MyViewModel {public IEnumerable Items {get; set; }}

where ItemViewModel :

 public class ItemViewModel { public string Name { get; set; } public bool Selected { get; set; } } 

and then your controller:

 public ActionResult Index() { var model = new MyViewModel { Items = new[] { new ItemViewModel() { Name= "Foo" }, new ItemViewModel() { Name= "Bar" } } }; return View(model); } [HttpPost] public ActionResult Index(MyViewModel model) { ... } 

and in view:

 @model MyViewModel <div> @using (Html.BeginForm()) { @Html.DisplayFor(x => x.Items) <button type="submit">OK</button> } </div> 

and in the editor template ( ~/Views/Shared/EditorTemplates/ItemViewModel.cshtml ):

 @model ItemViewModel <p> @Html.LabelFor(model => model.Selected, Model.Name) @Html.EditorFor(model => model.Selected) </p> 

Now it will work as expected.

+10
source

why are you using a model. Selected in

 @Html.LabelFor(model => model.Selected, Model.Name) 

will not work below code?

  @Html.LabelFor(model => model.Name) 
0
source

write foreach as

 for (int i = 0; i < Model.Count; i++) 

and then you can get attached like that

  Html.DisplayFor(model => model[i].Name) Html.EditorFor(model => model[i].Name) 

Then you can send a message.

0
source

thanks to Darin Dimitrov.

One more thing to add:

Names must match, otherwise he will not recognize it as a model. (for this example mySkills)

ViewData.TemplateInfo.HtmlFieldPrefix = " mySkills " + ViewData.TemplateInfo.HtmlFieldPrefix; ...

public ActionResult Create (List mySkills ...

0
source

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


All Articles