I am looking to implement a checkboxlist in ASP.NET Core, but am facing some difficulties.
My ViewModel:
public class GroupIndexViewModel
{
public
I just tried this and it worked:
<input asp-for="filter.type[i].IsEnabled"/>
without the checkbox, and then corresponding boolean value in model with hidden id and name.
Building on @dotnetstep's answer, I created a Tag Helper that takes a model of IEnumerable of SelectListItem and generates the fields described in his answer.
Here is the Tag Helper code:
[HtmlTargetElement(Attributes = "asp-checklistbox, asp-modelname")]
public class CheckListBoxTagHelper : TagHelper
{
[HtmlAttributeName("asp-checklistbox")]
public IEnumerable<SelectListItem> Items { get; set; }
[HtmlAttributeName("asp-modelname")]
public string ModelName { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var i = 0;
foreach (var item in Items)
{
var selected = item.Selected ? @"checked=""checked""" : "";
var disabled = item.Disabled ? @"disabled=""disabled""" : "";
var html = $@"<label><input type=""checkbox"" {selected} {disabled} id=""{ModelName}_{i}__Selected"" name=""{ModelName}[{i}].Selected"" value=""true"" /> {item.Text}</label>";
html += $@"<input type=""hidden"" id=""{ModelName}_{i}__Value"" name=""{ModelName}[{i}].Value"" value=""{item.Value}"">";
html += $@"<input type=""hidden"" id=""{ModelName}_{i}__Text"" name=""{ModelName}[{i}].Text"" value=""{item.Text}"">";
output.Content.AppendHtml(html);
i++;
}
output.Attributes.SetAttribute("class", "th-chklstbx");
}
}
You will need to add the following to the _ViewImports.cshtml file:
@addTagHelper *, <ProjectName>
Then to drop the check list box into your razor view it's as easy as:
<div asp-checklistbox="Model.Brands" asp-modelname="Brands"></div>
You might notice that I'm adding a class attribute to the div to style the box and it's content. Here is the CSS:
.th-chklstbx {
border: 1px solid #ccc;
padding: 10px 15px;
-webkit-border-radius: 5px ;
-moz-border-radius: 5px ;
-ms-border-radius: 5px ;
border-radius: 5px ;
}
.th-chklstbx label {
display: block;
margin-bottom: 10px;
}
You are not aware that you are already specifying the false
value to your input, since you're implementing a bad use of attributes.
Let's take a look at your view
@model GroupIndexViewModel
<form asp-action="Index" asp-controller="Group" method="get">
<ul>
@for (var i = 0; i < Model.Filters.Length; i++)
{
<li>
<input type="checkbox" id="@Model.Filters[i].Name" asp-for="@Model.Filters[i].Selected" value="@Model.Filters[i].Selected" checked="@Model.Filters[i].Selected" />
<label for="@Model.Filters[i].Name">@Model.Filters[i].Name</label>
</li>
}
</ul>
<button type="submit" name="action">Filtrer</button>
</form>
So, first. You are creating input elements from an array of Filter
. Now let's take a closer look at your input element.
<input type="checkbox" id="@Model.Filters[i].Name" asp-for="@Model.Filters[i].Selected" value="@Model.Filters[i].Selected" checked="@Model.Filters[i].Selected" />
Now, let me explain this.
type
attribute.id
attribute.asp-for
tag helper.value
attribute.checked
attribute.If you take a look at the Tag Helpers Documentation, you'll find the relationship between the .Net Type and the Input Type, understanding that:
Checkboxes holds a boolean value, corresponding to the model, and formatted by the tag helper as
type="checkbox"
.
Since you're using the type="checkbox"
attribute, the Tag Helper value can only be true
or false
. So, if we go back and look at the input element, you're already specifying a value to the input. Even though the tag-helper can assign a value to the input, it can't override the one already specified. Therefore, your input, will always have the value you've specified, in this case, a boolean
is always false by default.
Now you might think that your input element, has a false
value, and for instance, adding the checked="checked"
will not change the value to true
, since the value
attributes, overrides the checked
attribute. Causing a bad implementation of both attributes.
Therefore, you must use only one of the attributes. (Either the value
or the checked
). You can use them, for convenience. But in this case, you must use the default checked
attribute. Since you're implementing a Tag Helper, and the input value, have to be of type boolean
. And the checked
attribute value, returns a boolean and for instance, is the one used by the Tag Helper.
So the implementation provided by @dotnetstep should work, since it only declares the tag helper in the input element. So the Tag Helper, handles itself the corresponding attributes of the input.
@model GroupIndexViewModel
<form asp-action="Index" asp-controller="Group" method="get">
<ul>
@for (var i = 0; i < Model.Filters.Count; i++)
{
<li>
<input type="checkbox" asp-for="@Model.Filters[i].Selected" />
<label asp-for="@Model.Filters[i].Selected">@Model.Filters[i].Name</label>
<input type="hidden" asp-for="@Model.Filters[i].Id" />
<input type="hidden" asp-for="@Model.Filters[i].Name" />
</li>
}
</ul>
<button type="submit" name="action">Filtrer</button>
</form>
I would do following way.
@model GroupIndexViewModel
<form asp-action="Index" asp-controller="Group" method="get">
<ul>
@for (var i = 0; i < Model.Filters.Count; i++)
{
<li>
<input type="checkbox" asp-for="@Model.Filters[i].Selected" />
<label asp-for="@Model.Filters[i].Selected">@Model.Filters[i].Name</label>
<input type="hidden" asp-for="@Model.Filters[i].Id" />
<input type="hidden" asp-for="@Model.Filters[i].Name" />
</li>
}
</ul>
<button type="submit" name="action">Filtrer</button>
</form>
Here I assuming that you have proper implementation of controller and action.