I'm trying to make a list of checkboxes but the Html.LabelFor is not working.
It keeps generating <label for="">Some text</label>
, note the empty For
attribute.
I've tried a for and foreach loop before I tried using a display template but they all have this problem. I refuse to believe that writing the input fields by hand is the only solution. All help/tips are much appreciated.
public class MyViewModel
{
public string Name { get; set; }
public bool Selected { get; set; }
}
public ActionResult MyController()
{
var model = new List<MyViewModel>();
model.Add(new MyViewModel() { Name= "Foo" });
model.Add(new MyViewModel() { Name= "Bar" });
return View(model);
}
@model IEnumerable<MyViewModel>
<div>
@Html.DisplayFor(x => Model)
</div>
@model MyViewModel
<p>
@Html.LabelFor(model => model.Selected, Model.Name)
@Html.EditorFor(model => model.Selected)
</p>
<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 the <label>
isn't working as intended.
The thing is that since in your main view you directly have IEnumerable<MyViewModel>
, the prefix is [0].Selected
which the helpers doesn't like. You will also notice that your checkbox doesn't have an id. Here's a hack that you could employ 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 that your POST action argument is called model
:
[HttpPost]
public ActionResult Index(IEnumerable<MyViewModel> model) { ... }
which might not always be the case.
Also note that instead of @Html.DisplayFor(x => Model)
in your main view you could use @Html.EditorForModel()
.
Another possibility is to wrap this in a view model with a 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 the 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With