web-dev-qa-db-fra.com

Utilisez Html.RadioButtonFor et Html.LabelFor pour le même modèle mais des valeurs différentes

J'ai ce modèle de rasoir

<table>
<tr>
    <td>@Html.RadioButtonFor(i => i.Value, "1")</td>
    <td>@Html.LabelFor(i => i.Value, "true")</td>
</tr>
<tr>
    <td>@Html.RadioButtonFor(i => i.Value, "0")</td>
    <td>@Html.LabelFor(i => i.Value, "false")</td>
</tr>
</table>

Cela me donne ce code HTML

<table>
<tr>
    <td><input id="Items_1__Value" name="Items[1].Value" type="radio" value="1" /></td>
    <td><label for="Items_1__Value">true</label></td>
</tr>
<tr>
    <td><input checked="checked" id="Items_1__Value" name="Items[1].Value" type="radio" value="0" /></td>
    <td><label for="Items_1__Value">false</label></td>
</tr>
</table>

J'ai donc l'identifiant Items_1__Value deux fois, ce qui - bien sûr - n'est pas bon et ne fonctionne pas dans un navigateur lorsque je clique sur la deuxième étiquette "false", la première radio sera activée.

Je sais que je pourrais ajouter un identifiant propre à RadioButtonFor et y faire référence avec mon label, mais ce n'est pas très bon, n'est-ce pas? Surtout parce que je suis dans une boucle et que je ne peux pas simplement utiliser le nom "valeur" avec un nombre ajouté, cela se retrouverait également dans plusieurs ID Dom dans mon balisage HTML final.

Ne devrait pas être une bonne solution pour cela?

32
Marc

Je me demande comment MVC détermine les noms et les identifiants de champs "imbriqués". Il a fallu un peu de recherche sur le code source de MVC pour comprendre, mais je pense avoir une bonne solution pour vous.

Comment EditorTemplates et DisplayTemplates déterminent les noms de champs et les identifiants

Avec l'introduction de EditorTemplates et de DisplayTemplates, le framework MVC a ajouté ViewData.TemplateInfo qui contient, entre autres choses, le "préfixe de champ" actuel, tel que "Items[1].". Les modèles imbriqués l'utilisent pour créer des noms et des identifiants uniques.

Créez nos propres identifiants uniques:

La classe TemplateInfo contient une méthode intéressante, GetFullHtmlFieldId . Nous pouvons utiliser cela pour créer nos propres identifiants uniques, comme ceci: 

@{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("fieldName");}
@* This will result in something like "Items_1__fieldName" *@

Pour la victoire

Voici comment obtenir le comportement correct pour votre exemple:

<table>
<tr>
    @{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioTrue");}
    <td>@Html.RadioButtonFor(i => i.Value, "1", new{id})</td>
    <td>@Html.LabelFor(i => i.Value, "true", new{@for=id})</td>
</tr>
<tr>
    @{id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioFalse");}
    <td>@Html.RadioButtonFor(i => i.Value, "0", new{id})</td>
    <td>@Html.LabelFor(i => i.Value, "false", new{@for=id})</td>
</tr>
</table>

Ce qui vous donnera le code HTML suivant:

<table>
<tr>
    <td><input id="Items_1__radioTrue" name="Items[1].Value" type="radio" value="1" /></td>
    <td><label for="Items_1__radioTrue">true</label></td>
</tr>
<tr>
    <td><input checked="checked" id="Items_1__radioFalse" name="Items[1].Value" type="radio" value="0" /></td>
    <td><label for="Items_1__radioFalse">false</label></td>
</tr>
</table>

Avertissement

Ma syntaxe Razor est sous-développée, veuillez donc me faire savoir si ce code contient des erreurs de syntaxe.

Pour ce que ça vaut

Il est regrettable que cette fonctionnalité ne soit pas intégrée à RadioButtonFor. Il semble logique que tous les boutons radio rendus aient un ID combinant name ET value, mais ce n'est pas le cas - peut-être parce que cela serait différent de tous les autres assistants HTML.
Créer vos propres méthodes d’extension pour cette fonctionnalité semble également un choix logique. Cependant, l'utilisation de la "syntaxe d'expression" peut s'avérer délicate ... Je vous conseillerais donc de surcharger .RadioButton(name, value, ...) au lieu de RadioButtonFor(expression, ...). Et vous voudrez peut-être aussi une surcharge pour .Label(name, value).
J'espère que cela a du sens, car il y a beaucoup de «remplir les blancs» dans ce paragraphe.

47
Scott Rippey

Ne pas trop concevoir une solution pour cela. Tout ce que vous essayez d'accomplir, c'est que les boutons radio répondent aux clics sur le texte. Restez simple et enveloppez simplement vos boutons radio dans les étiquettes:

<table>
<tr>
    <td><label>@Html.RadioButtonFor(i => i.Value, "1")True</label></td>
</tr>
<tr>
    <td><label>@Html.RadioButtonFor(i => i.Value, "0")False</label></td>
</tr>
</table>

L’assistant LabelFor html est généralement utilisé pour importer le nom de l’attribut Affichage de votre modèle de vue (par exemple, "[Affichage (Nom =" Entrez votre nom ")]).

Avec les boutons radio, le nom n’est pas particulièrement utile, car vous avez une ligne de texte différente pour chaque bouton radio, ce qui signifie que vous êtes toujours coincé à coder le texte dans votre vue.

56
Roger Rouse

@ Scott Rippey l'a presque, mais je suppose qu'il doit utiliser une version différente de MVC3 car pour moi, @Html.LabelFor n'a pas de surcharge qui prendra 3 arguments. J'ai trouvé que l'utilisation du @Html.Label normal fonctionne très bien:

@{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioButton_True");}
@Html.Label(id, "True:")
@Html.RadioButtonFor(m => m.radioButton, true, new { id })

@{id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioButton_False");}
@Html.Label(id, "False:")
@Html.RadioButtonFor(m => m.radioButton, false, new { id })

cela vous permet de cliquer sur l'étiquette et de sélectionner le bouton radio associé, comme vous le souhaitez.

7
Ben

Pas parfait mais travail quand même,

<table>
<tr>
    <td>@ReplaceName(Html.RadioButtonFor(i => i.Value, "1"))</td>
    <td>@Html.LabelFor(i => i.Value[0], "true")</td>
</tr>
<tr>
    <td>@ReplaceName(Html.RadioButtonFor(i => i.Value, "0"))</td>
    <td>@Html.LabelFor(i => i.Value[1], "false")</td>
</tr>
</table>


@functions {
    int counter = 0;
    MvcHtmlString ReplaceName(MvcHtmlString html){
        return MvcHtmlString.Create(html.ToString().Replace("__Value", "__Value_" + counter++ +"_"));
    }
}
1
imran_ku07

Vous pouvez ajouter du texte avec des balises

<td>@Html.RadioButtonFor(i => i.Value, true) <text>True</text></td>
<td>@Html.RadioButtonFor(i => i.Value, false) <text>False</text></td>
0
Jannik

Voici un HtmlHelper que vous pouvez utiliser, bien que vous puissiez le personnaliser. Seulement à peine testé, donc YMMV. 

     public static MvcHtmlString RadioButtonWithLabelFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, object value, object htmlAttributes = null)
     {
        var name = ExpressionHelper.GetExpressionText(expression);
        var id = helper.ViewData.TemplateInfo.GetFullHtmlFieldId(name + "_" + value);

        var viewData = new ViewDataDictionary(helper.ViewData) {{"id", id}};

        if (htmlAttributes != null)
        {
            var viewDataDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            foreach (var keyValuePair in viewDataDictionary)
            {
                viewData[keyValuePair.Key] = keyValuePair.Value;
            }
        }

        var radioButton = helper.RadioButtonFor(expression, value, viewData);

        var tagBuilder = new TagBuilder("label");
        tagBuilder.MergeAttribute("for", id);
        tagBuilder.InnerHtml = value.ToString();

        return new MvcHtmlString(radioButton.ToHtmlString() + tagBuilder.ToString());
    }
0
Geoff