134 votes

ASP.NET MVC: pourquoi le CheckBoxFor rend-il une balise d'entrée supplémentaire et comment puis-je obtenir la valeur à l'aide de FormCollection?

Dans mon ASP.NET MVC application que je suis rendu une case à cocher utiliser le code suivant:

<%= Html.CheckBoxFor(i=>i.ReceiveRSVPNotifications) %>

Maintenant je vois que ce qui rend à la fois la case balise d'entrée et une face cachée de balise input. Le problème que je vais avoir, c'est quand j'essaie de récupérer la valeur de la case à cocher à l'aide de la FormCollection:

FormValues["ReceiveRSVPNotifications"]

J'obtiens la valeur "vrai", "faux". Lorsque l'on regarde le rendu HTML, je peux voir les suivants:

 <input id="ReceiveRSVPNotifications" name="ReceiveRSVPNotifications" value="true" type="checkbox">
 <input name="ReceiveRSVPNotifications" value="false" type="hidden">

Ainsi, le FormValues collection semble se joindre à ces deux valeurs, car ils ont le même nom. Des Idées?

171voto

Robert Harvey Points 103562

Jetez un oeil ici:

http://forums.asp.net/t/1314753.aspx

Ce n'est pas un bug, et est en fait la même approche que les deux Rubis sur Rails et MonoRail utilisation.

Lorsque vous soumettez un formulaire avec une case à cocher, la valeur est uniquement affiché si la case est cochée. Donc, si vous laissez la case décochée, puis rien ne sera envoyé au serveur lorsque dans de nombreuses situations, vous serait souhaitez faux pour être envoyé à la place. Caché entrée a le même nom comme la case à cocher, puis si la case n'est pas cochée, vous aurez toujours un "faux" envoyé au serveur.

Lorsque la case est cochée, le ModelBinder prendra automatiquement soins de l'extraction de la 'vraie' de la 'vrai', 'faux'

18voto

Chris Kemp Points 522

J'ai eu le même problème que Shawn (ci-dessus). Cette approche pourrait être excellente pour le POST, mais elle est vraiment désagréable pour GET. Par conséquent, j'ai implémenté une simple extension HTML qui extrait simplement le champ caché.

 public static MvcHtmlString BasicCheckBoxFor<T>(this HtmlHelper<T> html, 
                                                Expression<Func<T, bool>> expression,
                                                object htmlAttributes = null)
{
    var result = html.CheckBoxFor(expression).ToString();
    const string pattern = @"<input name=""[^""]+"" type=""hidden"" value=""false"" />";
    var single = Regex.Replace(result, pattern, "");
    return MvcHtmlString.Create(single);
}
 

Le problème que j'ai maintenant, c'est que je ne veux pas que le cadre MVC soit modifié pour que mon code soit rompu. Je dois donc m'assurer d'avoir une couverture de test expliquant ce nouveau contrat.

10voto

RyanJMcGowan Points 630

Voici le code source de la balise d’entrée supplémentaire. Microsoft a eu la gentillesse d'inclure des commentaires qui traitent de cette question avec précision.

         if (inputType == InputType.CheckBox)
        {
            // Render an additional <input type="hidden".../> for checkboxes. This
            // addresses scenarios where unchecked checkboxes are not sent in the request.
            // Sending a hidden input makes it possible to know that the checkbox was present
            // on the page when the request was submitted.
            StringBuilder inputItemBuilder = new StringBuilder();
            inputItemBuilder.Append(tagBuilder.ToString(TagRenderMode.SelfClosing));

            TagBuilder hiddenInput = new TagBuilder("input");
            hiddenInput.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden));
            hiddenInput.MergeAttribute("name", fullName);
            hiddenInput.MergeAttribute("value", "false");
            inputItemBuilder.Append(hiddenInput.ToString(TagRenderMode.SelfClosing));
            return MvcHtmlString.Create(inputItemBuilder.ToString());
        }
 

0voto

Jacob Brewer Points 308

Encore une autre solution:

 /// <summary>
/// If you posted an array of checkboxes to a controller, this will extract the values you expect.
/// </summary>
/// <param name="arrayOfCheckboxesFromController">An array of checkboxes passed to the controller</param>        
/// <remarks>with checkboxes, true values come with a twin false so remove it</remarks>
private static void GetCheckboxArrayValues(IList<bool> arrayOfCheckboxesFromController)
{
    for (var i = 0; i < arrayOfCheckboxesFromController.Count(); i++)
    {
        if (!arrayOfCheckboxesFromController[i]) continue;

        // This assumes the caller knows what they are doing and passed in an array of checkboxes posted to a controller
        arrayOfCheckboxesFromController.RemoveAt(i + 1);
    }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X