Attributs HTML conditionnels à l'aide de Razor MVC3

100

La variable strCSSClass a souvent une valeur mais est parfois vide.

Je ne veux pas inclure une classe vide = "" dans le HTML de cet élément d'entrée, ce qui signifie que si strCSSClass est vide, je ne veux pas du tout l'attribut class =.

Voici une façon de créer un attribut HTML conditionnel:

<input type="text" id="@strElementID" @(CSSClass.IsEmpty() ? "" : "class=" + strCSSClass) />

Existe-t-il une manière plus élégante de procéder? Plus précisément une où je pourrais suivre la même syntaxe que celle utilisée dans les autres parties de l'élément: class = "@ strCSSClass"?

tony722
la source

Réponses:

160

Vous ne l'avez pas entendu de ma part, le PM de Razor, mais dans Razor 2 (Pages Web 2 et MVC 4), nous aurons des attributs conditionnels intégrés à Razor (à partir de MVC 4 RC testé avec succès), vous pouvez donc simplement dire des choses comme ça ...

<input type="text" id="@strElementID" class="@strCSSClass" />

Si strCSSClass est nul, l'attribut class ne sera pas rendu du tout.

SSSHHH ... ne le dis pas. :)

Erik Porter
la source
1
Oui, vous ne devriez certainement pas accepter la mienne comme réponse. Cela dit, aujourd'hui, il n'y a pas de moyen plus propre de le faire (nous créons donc une façon plus propre de le faire). La façon la plus propre de le faire est probablement d'utiliser Html.TextBox, mais cela a un ensemble différent de choses moins souhaitables. :( Heureux que vous ayez aimé ce que nous ajoutons. :)
Erik Porter
1
Mais comment combiner les attributs Razor avec d'autres textes? Je dois faire ce qui suit: ... id = "[email protected]". Je m'attendais à quelque chose comme ... id = "track_2", mais il a généré la sortie suivante: ... id = "[email protected]" ...
Laserson
2
Vous pouvez forcer Razor à évaluer le code en mettant des parenthèses autour de celui-ci. id = "track _ @ (track.ID)"
Erik Porter
1
Ajout d'une note indiquant que cela fonctionne avec MVC 4. Si vous êtes sur MVC 3, voyez ma réponse ci-dessous.
AaronLS
4
@ErikPorter VEUILLEZ NE PAS MESSER AVEC MON HTML !! voir aussi stackoverflow.com/questions/9234467/… ceci aussi pour d'autres mauvais comportements
eaglestorm
126

Notez que vous pouvez faire quelque chose comme ça (au moins dans MVC3):

<td align="left" @(isOddRow ? "class=TopBorder" : "style=border:0px") >

Ce que je croyais être le rasoir ajoutant des citations était en fait le navigateur. Comme Rism l'a souligné lors des tests avec MVC 4 (je n'ai pas testé avec MVC 3 mais je suppose que le comportement n'a pas changé), cela produit en fait, class=TopBordermais les navigateurs sont capables d'analyser cette amende. Les analyseurs HTML sont quelque peu indulgents sur les guillemets d'attributs manquants, mais cela peut casser si vous avez des espaces ou certains caractères .

<td align="left" class="TopBorder" >

OU

<td align="left" style="border:0px" >

Qu'est-ce qui ne va pas avec la fourniture de vos propres devis

Si vous essayez d'utiliser certaines des conventions C # habituelles pour les guillemets imbriqués, vous vous retrouverez avec plus de guillemets que vous n'en avez négocié car Razor essaie de les échapper en toute sécurité. Par exemple:

<button type="button" @(true ? "style=\"border:0px\"" : string.Empty)>

Cela devrait être évalué à <button type="button" style="border:0px">mais Razor échappe toutes les sorties de C # et produit ainsi:

style=&quot;border:0px&quot;

Vous ne verrez cela que si vous affichez la réponse sur le réseau. Si vous utilisez un inspecteur HTML, vous voyez souvent le DOM, pas le HTML brut. Les navigateurs analysent le HTML dans le DOM, et la représentation DOM après analyse a déjà quelques subtilités appliquées. Dans ce cas, le navigateur voit qu'il n'y a pas de guillemets autour de la valeur d'attribut, les ajoute:

style="&quot;border:0px&quot;"

Mais dans l'inspecteur DOM, les codes de caractères HTML s'affichent correctement, donc vous voyez réellement:

style=""border:0px""

Dans Chrome, si vous cliquez avec le bouton droit de la souris et sélectionnez Modifier le code HTML, il revient en arrière pour que vous puissiez voir ces codes de caractères HTML désagréables, ce qui indique clairement que vous avez de vrais guillemets extérieurs et des guillemets intérieurs codés en HTML.

Donc, le problème lorsque vous essayez de faire les citations vous-même est que Razor leur échappe.

Si vous souhaitez un contrôle complet des devis

Utilisez Html.Raw pour empêcher l'échappement des guillemets:

<td @Html.Raw( someBoolean ? "rel='tooltip' data-container='.drillDown a'" : "" )>

Rend comme:

<td rel='tooltip' title='Drilldown' data-container='.drillDown a'>

Ce qui précède est parfaitement sûr car je ne génère aucun HTML à partir d'une variable. La seule variable impliquée est la condition ternaire. Cependant, sachez que cette dernière technique peut vous exposer à certains problèmes de sécurité si vous créez des chaînes à partir de données fournies par l'utilisateur. Par exemple, si vous avez créé un attribut à partir de champs de données provenant de données fournies par l'utilisateur, l'utilisation de Html.Raw signifie que la chaîne peut contenir une fin prématurée de l'attribut et de la balise, puis commencez une balise de script qui fait quelque chose au nom de la personne actuellement connectée. utilisateur (éventuellement différent de l'utilisateur connecté). Peut-être que vous avez une page avec une liste de toutes les images des utilisateurs et que vous définissez une info-bulle pour être le nom d'utilisateur de chaque personne, et un utilisateur s'est nommé'/><script>$.post('changepassword.php?password=123')</script> et maintenant tout autre utilisateur qui consulte cette page voit son mot de passe immédiatement changé en un mot de passe connu de l'utilisateur malveillant.

AaronLS
la source
C'est un très bon point! Et en fait, cela le rend lisible et utilisable dans la plupart des situations.
Dmytro Shevchenko
C'est ce que je faisais dans l'exemple de ma question. Merci pour une explication et un exemple plus élaborés. :)
tony722
1
Attention cependant aux espaces. "style = affichage: aucun;" rend comme aucun; = "": = "" style = "display"
wmcainsh
1
Alors pourquoi cela ne fonctionne-t-il pas re: guillemets doubles magiques <span @ (true? "Class = logo-owner": string.Empty) /> Cela produit simplement <span class = logo-owner />
rism
1
@AaronLS Oui, c'est exactement comme ça qu'ils sont. Je ne comprends pas comment le navigateur (Chrome 40 / FF33.1 / IE 10) affecterait quoi que ce soit puisqu'il s'agit d'un balisage généré par le serveur et si oui, comment se fait-il que ces deux attributs de classe mais pas pour l'attribut de classe du bouton demander ou même le type = Attributs "bouton" des trois boutons. Certainement une chose de serveur IMHO puisque je peux également RDP dans quelques machines virtuelles Azure disséminées dans le monde entier pour le même résultat IE / Firefox / Chrome.
rism
12

J'imagine qu'un moyen un peu plus pratique et structuré est d'utiliser l'aide Html. À votre avis, cela peut ressembler à:

@{
 var htmlAttr = new Dictionary<string, object>();
 htmlAttr.Add("id", strElementId);
 if (!CSSClass.IsEmpty())
 {
   htmlAttr.Add("class", strCSSClass);
 }
}

@* ... *@

@Html.TextBox("somename", "", htmlAttr)

Si cette méthode vous est utile, je vous recommande de définir le dictionnaire htmlAttrdans votre modèle afin que votre vue n'ait pas besoin de @{ }blocs logiques (soyez plus clair).

Yaschur
la source
4
-1, ne recommandez jamais à quelqu'un de mettre de la logique dans les vues. Les vues ne devraient être responsables que du rendu. Ajoutez plutôt un exemple HtmlHelper et je vous donnerai +1.
jgauffin
1
Pour tester les choses, je peux utiliser le bloc de code en vue - c'est plus rapide. Et ma recommandation était de déplacer ce bloc dans le modèle.
Yaschur
3
oui, mais les réponses doivent montrer les meilleures pratiques et non la version rapide et sale qui fait de la maintenance du code un cauchemar.
jgauffin
@jgauffin Je pense que l'aide Html ici est inutile. voir ma réponse.
gdoron soutient Monica
+1 @Yaschur Votre réponse est inspirante. Continuez votre bon travail. c'est à dire. avec la fonction de conversion explicite C #, nous pouvons encore améliorer cette réponse. Tout le code n'a pas dû être façonné d'une certaine manière. Il y a toujours une meilleure façon dont nous ne sommes pas conscients. Et certains projets sont en faveur de l'organisation du code. L'organisation du code n'est par pratique pas des concepts!
Bamboo