Je cherche à implémenter une liste de contrôle dans ASP.NET Core, mais je suis confronté à des difficultés.
Mon ViewModel:
public class GroupIndexViewModel
{
public Filter[] Filters { get; set; }
}
public class Filter
{
public int Id { get; set; }
public string Name { get; set; }
public bool Selected { get; set; }
}
Mon avis:
@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>
Lors de la publication sur mon contrôleur, la propriété Filter de mon modèle de vue affiche false sélectionnée même si elle est sélectionnée dans la vue.
Je referais le chemin suivant.
@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>
Ici, je suppose que vous avez une implémentation correcte du contrôleur et de l’action.
Vous ne savez pas que vous spécifiez déjà la valeur false
à votre entrée, car vous implémentez une mauvaise utilisation des attributs.
_ {Jetons un coup d'oeil à ta vue} _
@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>
Alors, d'abord. Vous créez des éléments d'entrée à partir d'un tableau de Filter
. Examinons maintenant de plus près votre élément d’entrée.
<input type="checkbox" id="@Model.Filters[i].Name" asp-for="@Model.Filters[i].Selected" value="@Model.Filters[i].Selected" checked="@Model.Filters[i].Selected" />
Maintenant, laissez-moi expliquer cela.
type
.id
.asp-for
.value
.checked
.Si vous examinez le Tag Helpers Documentation , vous découvrirez la relation entre Type. Net et Type d'entrée, en comprenant que:
Les cases à cocher contiennent une valeur booléenne correspondant au modèle et formatée par l'assistant de balise en tant que
type="checkbox"
.
Puisque vous utilisez l'attribut type="checkbox"
, la valeur Tag Helper ne peut être que true
ou false
. Donc, si nous revenons en arrière et examinons l'élément input, vous spécifiez déjà une valeur pour l'entrée. Même si le tag-helper peut affecter une valeur à l'entrée, il ne peut pas remplacer celle déjà spécifiée. Par conséquent, votre entrée aura toujours la valeur que vous avez spécifiée, dans ce cas, une boolean
est toujours false par défaut.
Vous pouvez maintenant penser que votre élément d’entrée a une valeur false
et que, par exemple, ajouter le checked="checked"
ne le sera pas changer la valeur en true
, puisque les attributs value
remplacent l’attribut checked
. Causer une mauvaise implémentation des deux attributs.
Par conséquent, vous devez utiliser un seul des attributs. (Soit le value
ou le checked
). Vous pouvez les utiliser, pour plus de commodité. Mais dans ce cas, vous devez utilisez l'attribut checked
par défaut. Puisque vous implémentez Tag Helper et que la valeur en entrée doit être de type boolean
. Et la valeur de l'attribut checked
, renvoie un booléen et, par exemple, est celui utilisé par l'assistant de balise.
Donc, l'implémentation fournie par @dotnetstep devrait fonctionner, car elle ne déclare que le tag helper dans l'élément input. Ainsi, l’assistant de balise gère lui-même les attributs correspondants de l’entrée.
@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>
En me basant sur la réponse de @ dotnetstep, j'ai créé un assistant de tag qui prend un modèle de IEnumerable de SelectListItem et génère les champs décrits dans sa réponse.
Voici le code Tag Helper:
[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");
}
}
Vous devrez ajouter les éléments suivants au fichier _ViewImports.cshtml:
@addTagHelper *, <ProjectName>
Ensuite, pour déposer la liste de contrôle dans votre vue rasoir, rien de plus simple:
<div asp-checklistbox="Model.Brands" asp-modelname="Brands"></div>
Vous remarquerez peut-être que j'ai ajouté un attribut de classe à la div pour styliser la boîte et son contenu. Voici le 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;
}
Je viens d'essayer cela et cela a fonctionné:
<input asp-for="filter.type[i].IsEnabled"/>
sans la case à cocher, puis la valeur booléenne correspondante dans le modèle avec un identifiant et un nom masqués.