Atributos HTML condicionales usando Razor MVC3

100

La variable strCSSClass a menudo tiene un valor, pero a veces está vacía.

No quiero incluir un class = "" vacío en el HTML de este elemento de entrada, lo que significa que si strCSSClass está vacío, no quiero el atributo class = en absoluto.

La siguiente es una forma de hacer un atributo HTML condicional:

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

¿Existe una forma más elegante de hacer esto? Específicamente uno en el que podría seguir la misma sintaxis que se usa en las otras partes del elemento: class = "@ strCSSClass"?

tony722
fuente

Respuestas:

160

No lo escuchó de mí, el PM de Razor, pero en Razor 2 (Web Pages 2 y MVC 4) tendremos atributos condicionales integrados en Razor (a partir de MVC 4 RC probado con éxito), por lo que solo puede decir cosas como esta ...

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

Si strCSSClass es nulo, el atributo de clase no se representará en absoluto.

SSSHHH ... no lo digas. :)

Erik Porter
fuente
1
Sí, definitivamente no deberías aceptar la mía como la respuesta. Dicho esto, hoy no hay una forma más limpia de hacerlo (por lo tanto, estamos creando una forma más limpia de hacerlo). Probablemente la forma más limpia de hacerlo es usar Html.TextBox, pero tiene un conjunto diferente de cosas menos deseables. :( Sin embargo, me alegro de que te guste lo que estamos agregando. :)
Erik Porter
1
Pero, ¿cómo puedo combinar los atributos de Razor con otro texto? Necesito hacer lo siguiente: ... id = "[email protected]". Esperaba algo como ... id = "track_2", pero generó el siguiente resultado: ... id = "[email protected]" ...
Laserson
2
Puede obligar a Razor a evaluar el código colocando paréntesis alrededor. id = "track _ @ (track.ID)"
Erik Porter
1
Se agregó una nota que indica que esto funciona correctamente con MVC 4. Si está en MVC 3, vea mi respuesta a continuación.
AaronLS
4
@ErikPorter ¡¡POR FAVOR NO HAGA ENROLLAR MI HTML !! también vea stackoverflow.com/questions/9234467/… esto también para otros malos comportamientos
eaglestorm
126

Tenga en cuenta que puede hacer algo como esto (al menos en MVC3):

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

Lo que yo creía que era una navaja para agregar comillas era en realidad el navegador. Como señaló Rism al probar con MVC 4 (no he probado con MVC 3 pero supongo que el comportamiento no ha cambiado), esto en realidad produce, class=TopBorderpero los navegadores pueden analizar esto bien. Los analizadores de HTML son algo indulgentes con las comillas de atributos faltantes, pero esto puede romperse si tiene espacios o ciertos caracteres .

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

O

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

¿Qué falla al proporcionar sus propias cotizaciones?

Si intenta utilizar algunas de las convenciones habituales de C # para las citas anidadas, terminará con más citas de las que esperaba porque Razor está tratando de escapar de ellas de forma segura. Por ejemplo:

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

Esto debería evaluar a, <button type="button" style="border:0px">pero Razor escapa de todos los resultados de C # y, por lo tanto, produce:

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

Solo verá esto si ve la respuesta en la red. Si usa un inspector de HTML, a menudo verá el DOM, no el HTML sin formato. Los navegadores analizan HTML en el DOM, y la representación DOM posterior al análisis ya tiene algunas sutilezas aplicadas. En este caso, el navegador ve que no hay comillas alrededor del valor del atributo, las agrega:

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

Pero en el inspector DOM, los códigos de caracteres HTML se muestran correctamente para que realmente vea:

style=""border:0px""

En Chrome, si hace clic con el botón derecho y selecciona Editar HTML, vuelve a cambiar para que pueda ver esos desagradables códigos de caracteres HTML, lo que deja en claro que tiene comillas exteriores reales y comillas interiores codificadas en HTML.

Entonces, el problema de intentar hacer las citas usted mismo es que Razor se les escapa.

Si quieres un control total de las cotizaciones

Utilice Html.Raw para evitar que las comillas escapen:

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

Se renderiza como:

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

Lo anterior es perfectamente seguro porque no estoy generando ningún HTML desde una variable. La única variable involucrada es la condición ternaria. Sin embargo, tenga en cuenta que esta última técnica podría exponerlo a ciertos problemas de seguridad si crea cadenas a partir de datos proporcionados por el usuario. Por ejemplo, si creó un atributo a partir de campos de datos que se originaron a partir de datos proporcionados por el usuario, el uso de Html.Raw significa que la cadena podría contener una terminación prematura del atributo y la etiqueta, luego comience una etiqueta de secuencia de comandos que haga algo en nombre del usuario actualmente conectado usuario (posiblemente diferente al usuario que inició sesión). Tal vez tenga una página con una lista de todas las imágenes de los usuarios y esté configurando una información sobre herramientas para que sea el nombre de usuario de cada persona, y un usuario se nombró a sí mismo'/><script>$.post('changepassword.php?password=123')</script> y ahora cualquier otro usuario que vea esta página cambia instantáneamente su contraseña a una contraseña que el usuario malintencionado conoce.

AaronLS
fuente
¡Ese es un muy buen punto! Y, de hecho, lo hace legible y utilizable en la mayoría de situaciones.
Dmytro Shevchenko
Eso es lo que estaba haciendo en el ejemplo de mi pregunta. Gracias por una explicación y un ejemplo más elaborados. :)
tony722
1
Sin embargo, tenga cuidado con los espacios. "estilo = pantalla: ninguno;" se representa como none; = "": = "" style = "display"
wmcainsh
1
Entonces, ¿por qué esto no funciona re: comillas dobles mágicas <span @ (true? "Class = logo-owner": string.Empty) /> Simplemente produce <span class = logo-owner />
rism
1
@AaronLS Sí, así son exactamente. No puedo entender cómo el navegador (Chrome 40 / FF33.1 / IE 10) afectaría algo, ya que este es un marcado generado por el servidor y, de ser así, ¿por qué solo esos dos atributos de clase, pero no el atributo de clase del botón de preguntar o incluso el tipo = atributos de "botón" de los tres botones. Definitivamente una cosa de servidor en mi humilde opinión, ya que también puedo RDP en un par de máquinas virtuales de Azure repartidas por todo el mundo para el mismo resultado IE / Firefox / Chrome.
rism
12

Supongo que una forma un poco más conveniente y estructurada es usar el ayudante Html. En su opinión, puede verse así:

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

@* ... *@

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

Si esta forma le resulta útil, le recomiendo definir el diccionario htmlAttren su modelo para que su vista no necesite ningún @{ }bloque lógico (sea más claro).

Yaschur
fuente
4
-1, nunca recomiendo a alguien que ponga lógica en las vistas. Las vistas solo deberían ser responsables de la renderización. Agregue un ejemplo de HtmlHelper en su lugar y le daré +1.
jgauffin
1
Para probar cosas, puedo usar el bloque de código a la vista, es más rápido. Y mi recomendación fue mover este bloque al modelo.
Yaschur
3
sí, pero las respuestas deben mostrar las mejores prácticas y no la versión rápida y sucia que hace que el mantenimiento del código sea una pesadilla.
jgauffin
@jgauffin Creo que el ayudante HTML aquí es innecesario. mira mi respuesta.
gdoron apoya a Monica el
+1 @Yaschur Tu respuesta es inspiradora. Sigan con el buen trabajo. es decir. Con la función de conversión explícita de C #, podemos mejorar esta respuesta aún más. No todo el código tenía que tener una forma determinada. Siempre hay una forma mejor de la que no somos conscientes. Y algunos proyectos están a favor de la organización del código. En la práctica, la organización del código no es conceptos.
Bamboo