Comment gérer les cases à cocher dans ASP.NET formulaires MVC?
Attention: cette question a plus de neuf ans!
Votre meilleure option est de rechercher des questions plus récentes, ou de rechercher les réponses ci-dessous à la recherche de votre version spécifique de MVC, car beaucoup de réponses ici sont obsolètes maintenant.
Si vous trouvez une réponse qui fonctionne pour votre version, assurez-vous que la réponse contient la version de MVC que vous utilisez.
(La question d'origine commence en dessous)
Cela me semble un peu bizarre, mais pour autant que Je peux dire, ce est comment vous le faites.
J'ai une collection d'objets, et je veux que les utilisateurs en sélectionnent un ou plusieurs. Cela me dit "formulaire avec des cases à cocher."Mes objets n'ont aucun concept de "sélectionné" (ils sont des POCO rudimentaires formés en désérialisant un appel wcf). Donc, je fais ce qui suit:
public class SampleObject{
public Guid Id {get;set;}
public string Name {get;set;}
}
Dans la vue:
<%
using (Html.BeginForm())
{
%>
<%foreach (var o in ViewData.Model) {%>
<%=Html.CheckBox(o.Id)%> <%= o.Name %>
<%}%>
<input type="submit" value="Submit" />
<%}%>
Et, dans le contrôleur, c'est le seul moyen que je peux voir pour comprendre quels objets l'Utilisateur a vérifiés:
public ActionResult ThisLooksWeird(FormCollection result)
{
var winnars = from x in result.AllKeys
where result[x] != "false"
select x;
// yadda
}
C'est bizarre dans le premier place, et deuxièmement, pour les éléments que l'Utilisateur a vérifiés, FormCollection répertorie sa valeur comme "true false" plutôt que simplement true.
De toute évidence, il me manque quelque chose. Je pense que cela est construit avec l'idée que les objets de la collection qui sont utilisés dans le formulaire html sont mis à jour en utilisant UpdateModel()
ou via un ModelBinder.
Mais mes objets ne sont pas configurés pour cela; cela signifie-t-il que c'est le seul moyen? Est-il une autre façon de le faire?
22 réponses
Html.CheckBox fait quelque chose de bizarre-si vous affichez la source sur la page résultante, vous verrez qu'un <input type="hidden" />
est généré à côté de chaque case à cocher, ce qui explique les valeurs "true false" que vous voyez pour chaque élément de formulaire.
Essayez ceci, qui fonctionne définitivement sur ASP.NET MVC Beta parce que je viens de l'essayer.
Mettez ceci dans la vue au lieu d'utiliser Html.Checkbox (case à cocher):
<% using (Html.BeginForm("ShowData", "Home")) { %>
<% foreach (var o in ViewData.Model) { %>
<input type="checkbox" name="selectedObjects" value="<%=o.Id%>">
<%= o.Name %>
<%}%>
<input type="submit" value="Submit" />
<%}%>
Vos cases à cocher sont toutes appelées selectedObjects
, et le value
de chaque case à cocher est le GUID du objet correspondant.
Puis postez à l'action de contrôleur suivante (ou quelque chose de similaire qui fait quelque chose d'utile au lieu de la réponse.Ecrire ())
public ActionResult ShowData(Guid[] selectedObjects) {
foreach (Guid guid in selectedObjects) {
Response.Write(guid.ToString());
}
Response.End();
return (new EmptyResult());
}
Cet exemple écrira simplement les GUID des cases que vous avez cochées; ASP.NET MVC mappe les valeurs GUID des cases à cocher sélectionnées dans le paramètre Guid[] selectedObjects
pour vous, et analyse même les chaînes de la requête.Formez la collection en objets GUID instanciés, ce qui je pense est plutôt agréable.
HtmlHelper ajoute une entrée cachée pour informer le contrôleur de l'état non coché. Donc, pour avoir le statut vérifié correct:
bool bChecked = form[key].Contains("true");
Dans le cas où vous vous demandez pourquoi ils ont mis un champ caché avec le même nom que la case à cocher, la raison est la suivante:
Commentaire du code source MVCBetaSource\MVC\src\MvcFutures\Mvc \ ButtonsAndLinkExtensions.cs
Rend un
<input type="hidden".../>
supplémentaire pour les cases à cocher. Cela concerne les scénarios où les cases non cochées ne sont pas envoyées demande. Envoi d'une entrée cachée permet de savoir que l' case à cocher était présent sur la page lorsque le la demande a été soumise.
Je suppose que dans les coulisses, ils doivent le savoir pour se lier aux paramètres sur les méthodes d'action du contrôleur. Vous pourriez alors avoir un booléen à trois états je suppose (lié à un paramètre bool nullable). Je ne l'ai pas essayé mais j'espère que c'est ce qu'ils ont fait.
Vous devez également utiliser <label for="checkbox1">Checkbox 1</label>
car les gens peuvent alors cliquer sur le texte de l'étiquette ainsi que sur la case à cocher elle-même. Il est également plus facile de style et au moins dans IE il sera mis en évidence lorsque vous tabulez à travers les contrôles de la page.
<%= Html.CheckBox("cbNewColors", true) %><label for="cbNewColors">New colors</label>
Ce n'est pas juste une chose "oh je pourrais le faire". C'est une amélioration significative de l'expérience utilisateur. Même si tous les utilisateurs peuvent cliquer sur l'étiquette de beaucoup de volonté.
Je suis surpris qu'aucune de ces réponses n'utilise les fonctionnalités MVC intégrées pour cela.
J'ai écrit un article de blog à ce sujet ici , qui relie même les étiquettes à la case à cocher. J'ai utilisé le dossier EditorTemplate pour y parvenir de manière propre et modulaire.
Vous finirez simplement avec un nouveau fichier dans le dossier EditorTemplate qui ressemble à ceci:
@model SampleObject
@Html.CheckBoxFor(m => m.IsChecked)
@Html.HiddenFor(m => m.Id)
@Html.LabelFor(m => m.IsChecked, Model.Id)
Dans votre vue réelle, il n'y aura pas besoin de boucler ceci, simplement 1 ligne de code:
@Html.EditorFor(x => ViewData.Model)
Visiter mon blog pour plus de détails.
Voici ce que j'ai fait.
Vue:
<input type="checkbox" name="applyChanges" />
Contrôleur:
var checkBox = Request.Form["applyChanges"];
if (checkBox == "on")
{
...
}
J'ai trouvé le Html.* les méthodes d'aide ne sont pas si utiles dans certains cas, et que je ferais mieux de le faire en HTML ancien. Ceci étant l'un d'eux, l'autre qui vient à l'esprit est des boutons radio.
Edit: c'est sur Preview 5, évidemment YMMV entre les versions.
Ils semblent choisir de lire la première valeur uniquement, donc c'est" true "lorsque la case est cochée, et" false " lorsque seule la valeur cachée est incluse. Ceci est facilement récupéré avec du code comme ceci:
model.Property = collection["ElementId"].ToLower().StartsWith("true");
@Dylan Beattie Grande Trouvaille!!! Je vous Remercie beaucoup. Pour étendre encore plus loin, cette technique fonctionne également parfaitement avec L'approche du modèle de vue. MVC est tellement cool, il est assez intelligent pour lier un tableau de GUID à une propriété du même nom que l'objet modèle lié à la vue. Exemple:
ViewModel:
public class SampleViewModel
{
public IList<SampleObject> SampleObjectList { get; set; }
public Guid[] SelectedObjectIds { get; set; }
public class SampleObject
{
public Guid Id { get; set; }
public string Name { get; set; }
}
}
Vue:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Sample View</h2>
<table>
<thead>
<tr>
<th>Checked</th>
<th>Object Name</th>
</tr>
</thead>
<% using (Html.BeginForm()) %>
<%{%>
<tbody>
<% foreach (var item in Model.SampleObjectList)
{ %>
<tr>
<td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
<td><%= Html.Encode(item.Name)%></td>
</tr>
<% } %>
</tbody>
</table>
<input type="submit" value="Submit" />
<%}%>
Contrôleur:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult SampleView(Guid id)
{
//Object to pass any input objects to the View Model Builder
BuilderIO viewModelBuilderInput = new BuilderIO();
//The View Model Builder is a conglomerate of repositories and methods used to Construct a View Model out of Business Objects
SampleViewModel viewModel = sampleViewModelBuilder.Build(viewModelBuilderInput);
return View("SampleView", viewModel);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SampleView(SampleViewModel viewModel)
{
// The array of Guids successfully bound to the SelectedObjectIds property of the View Model!
return View();
}
Toute personne familière avec la philosophie du modèle de vue se réjouira, cela fonctionne comme un champion!
Je voudrais également souligner que vous pouvez nommer chaque case à cocher un nom différent, et que ce nom fait partie des paramètres actionresults.
Exemple,
Vue:
<%= Html.CheckBox("Rs232CheckBox", false, new { @id = "rs232" })%>RS-232
<%= Html.CheckBox("Rs422CheckBox", false, new { @id = "rs422" })%>RS-422
Contrôleur:
public ActionResults MyAction(bool Rs232CheckBox, bool Rs422CheckBox) {
...
}
Les valeurs de la vue sont transmises à l'action puisque les noms sont les mêmes.
Je sais que cette solution n'est pas idéale pour votre projet, mais j'ai pensé lancer l'idée là-bas.
<input type = "checkbox" name = "checkbox1" /> <label> Check to say hi.</label>
Du contrôleur:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection fc)
{
var s = fc["checkbox1"];
if (s == "on")
{
string x = "Hi";
}
}
Ce problème se produit également dans la version 1.0. HTML.Checkbox () provoque l'ajout d'un autre champ masqué avec le même nom/id que celui de votre case à cocher d'origine. Et comme j'essayais de charger un tableau de cases à cocher en utilisant le document.GetElemtentsByName (), vous pouvez deviner comment les choses se sont gâtées. C'est une bizarre.
D'après ce que je peux rassembler, le modèle ne veut pas deviner si checked = true ou false, j'ai contourné cela en définissant un attribut de valeur sur l'élément checkbox avec jQuery avant de soumettre le formulaire comme ceci:
$('input[type="checkbox"]').each(function () {
$(this).attr('value', $(this).is(':checked'));
});
De cette façon, vous n'avez pas besoin d'un élément caché juste pour stocker la valeur de la case à cocher.
Je sais que cette question a été écrite quand MVC3 n'était pas sorti, mais pour tous ceux qui viennent à cette question et utilisent MVC3, vous pouvez vouloir la façon "correcte" de le faire.
Alors je pense que faire l'ensemble
Contains("true");
La chose est géniale et propre, et fonctionne sur toutes les versions MVC, le problème est qu'elle ne prend pas en compte la culture (comme si cela importait vraiment dans le cas d'un bool).
La "bonne" façon de comprendre la valeur d'un booléen, au moins dans MVC3, est d'utiliser la ValueProvider.
var value = (bool)ValueProvider.GetValue("key").ConvertTo(typeof(bool));
Je le fais dans l'un des sites de mon client lorsque je modifie les autorisations:
var allPermissionsBase = Request.Params.AllKeys.Where(x => x.Contains("permission_")).ToList();
var allPermissions = new List<KeyValuePair<int, bool>>();
foreach (var key in allPermissionsBase)
{
// Try to parse the key as int
int keyAsInt;
int.TryParse(key.Replace("permission_", ""), out keyAsInt);
// Try to get the value as bool
var value = (bool)ValueProvider.GetValue(key).ConvertTo(typeof(bool));
}
Maintenant, la beauté de ceci est que vous pouvez l'utiliser avec tout type simple, et il sera même correcte, basée sur la Culture (pensez à l'argent, les décimales, etc).
Le ValueProvider est ce qui est utilisé lorsque vous formez vos Actions comme ceci:
public ActionResult UpdatePermissions(bool permission_1, bool permission_2)
Mais lorsque vous essayez de construire dynamiquement ces listes et de vérifier les valeurs, vous ne connaîtrez jamais L'Id au moment de la compilation, donc vous devez les traiter à la volée.
La façon la plus simple de le faire est de le faire...
Vous définissez le nom et la valeur.
<input type="checkbox" name="selectedProducts" value="@item.ProductId" />@item.Name
Ensuite, lors de la soumission, récupérez les valeurs des cases à cocher et enregistrez-les dans un tableau int. ensuite, la fonction LinQ appropriée. C'est tout..
[HttpPost]
public ActionResult Checkbox(int[] selectedObjects)
{
var selected = from x in selectedObjects
from y in db
where y.ObjectId == x
select y;
return View(selected);
}
Identique à la réponse de nautic20, utilisez simplement la liste de cases à cocher MVC default model binding avec le même nom qu'une propriété de collection de string / int/enum dans ViewModel. Qui est-il.
Mais un problème doit être souligné. Dans chaque composant de case à cocher, vous ne devez pas y mettre "Id", ce qui affectera la liaison du modèle MVC.
Le code suivant fonctionnera pour la liaison du modèle:
<% foreach (var item in Model.SampleObjectList)
{ %>
<tr>
<td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
<td><%= Html.Encode(item.Name)%></td>
</tr>
<% } %>
Les codes suivants ne seront pas liés au modèle (la différence ici est l'id assigné pour chaque case à cocher)
<% foreach (var item in Model.SampleObjectList)
{ %>
<tr>
<td><input type="checkbox" name="SelectedObjectIds" id="[some unique key]" value="<%= item.Id%>" /></td>
<td><%= Html.Encode(item.Name)%></td>
</tr>
<% } %>
C'est ce que j'ai fait pour perdre les valeurs doubles lors de l'utilisation du Html.case(...
Replace("true,false","true").Split(',')
Avec 4 cases cochées, décochées, décochées, cochées il tourne true,false,false,false,true,false dans vrai,faux,faux,vrai. juste ce dont j'avais besoin
Que diriez-vous de quelque chose comme ça?
bool isChecked = false;
if (Boolean.TryParse(Request.Form.GetValues(”chkHuman”)[0], out isChecked) == false)
ModelState.AddModelError(”chkHuman”, “Nice try.”);
Lors de l'utilisation de la case à cocher HtmlHelper, je préfère de loin travailler avec les données de formulaire de case à cocher affichées en tant que tableau. Je ne sais pas vraiment pourquoi, je sais que les autres méthodes fonctionnent, mais je pense que je préfère simplement traiter les chaînes séparées par des virgules comme un tableau autant que possible.
Faire un test 'vérifié' ou vrai serait:
//looking for [true],[false]
bool isChecked = form.GetValues(key).Contains("true");
Faire une fausse vérification serait:
//looking for [false],[false] or [false]
bool isNotChecked = !form.GetValues(key).Contains("true");
La principale différence est d'utiliser GetValues
car cela renvoie comme un tableau.
Faites simplement ceci sur $(document).ready
:
$('input:hidden').each(function(el) {
var that = $(this)[0];
if(that.id.length < 1 ) {
console.log(that.id);
that.parentElement.removeChild(that);
}
});
Ma solution est:
<input type="checkbox" id="IsNew-checkbox" checked="checked" />
<input type="hidden" id="IsNew" name="IsNew" value="true" />
<script language="javascript" type="text/javascript" >
$('#IsNew-checkbox').click(function () {
if ($('#IsNew-checkbox').is(':checked')) {
$('#IsNew').val('true');
} else {
$('#IsNew').val('false');
}
});
</script>
Plus vous pouvez trouver ici: http://www.blog.mieten.pl/2010/12/asp-net-mvc-custom-checkbox-as-solution-of-string-was-not-recognized-as-a-valid-boolean/
J'ai eu presque le même problème mais la valeur de retour de mon contrôleur a été bloquée avec d'autres valeurs.
Trouvé une Solution simple, mais il semble un peu rugueux.
Essayez de type Viewbag.
dans votre Contrôleur et maintenant vous lui donner un nom comme Viewbag.Checkbool
Maintenant, passez à la vue et essayez ceci @Viewbag.Checkbool
avec ceci, vous obtiendrez la valeur du contrôleur.
Mes paramètres de contrôleur ressemblent à ceci:
public ActionResult Anzeigen(int productid = 90, bool islive = true)
Et ma case à cocher se mettra à jour comme ceci:
<input id="isLive" type="checkbox" checked="@ViewBag.Value" ONCLICK="window.location.href = '/MixCategory/Anzeigen?isLive=' + isLive.checked.toString()" />
En utilisant @mmacaulay, je suis venu avec ceci pour bool:
// MVC Work around for checkboxes.
bool active = (Request.Form["active"] == "on");
Si cochée active = true
Si non cochée active = false