Attributi HTML condizionali che utilizzano Razor MVC3


100

La variabile strCSSClass ha spesso un valore ma a volte è vuota.

Non voglio includere una classe vuota = "" nell'HTML di questo elemento di input, il che significa che se strCSSClass è vuoto, non voglio affatto l'attributo class =.

Il seguente è un modo per eseguire un attributo HTML condizionale:

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

C'è un modo più elegante per farlo? In particolare uno in cui potrei seguire la stessa sintassi utilizzata nelle altre parti dell'elemento: class = "@ strCSSClass"?

Risposte:


160

Non l'hai sentito da me, il PM per Razor, ma in Razor 2 (pagine Web 2 e MVC 4) avremo attributi condizionali incorporati in Razor (a partire da MVC 4 RC testato con successo), quindi puoi semplicemente dire cose come questa ...

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

Se strCSSClass è null, l'attributo class non verrà visualizzato affatto.

SSSHHH ... non dirlo. :)


1
Sì, sicuramente non dovresti accettare la mia come risposta. Detto questo, oggi non esiste un modo più pulito per farlo (quindi stiamo creando un modo più pulito per farlo). Probabilmente il modo più pulito per farlo è usare Html.TextBox, ma questo ha un insieme diverso di cose meno desiderabili. :( Sono contento che ti piaccia quello che stiamo aggiungendo però. :)
Erik Porter

1
Ma come posso combinare gli attributi Razor con altro testo? Devo fare quanto segue: ... id = "track_@track.ID". Mi aspettavo qualcosa come ... id = "track_2", ma ha generato il seguente output: ... id = "track_@track.ID" ...
Laserson

2
Puoi forzare Razor a valutare il codice inserendo parentesi attorno ad esso. id = "track _ @ (track.ID)"
Erik Porter

1
Aggiunta nota che indica che funziona correttamente con MVC 4. Se sei su MVC 3 vedi la mia risposta di seguito.
AaronLS

4
@ErikPorter PER FAVORE, NON MANCARE IL MIO HTML !! anche vedere stackoverflow.com/questions/9234467/... questo pure per altri cattivo comportamento
eaglestorm

126

Nota che puoi fare qualcosa del genere (almeno in MVC3):

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

Quello che credevo fosse un rasoio che aggiungeva virgolette era in realtà il browser. Come ha sottolineato Rism durante il test con MVC 4 (non ho testato con MVC 3 ma presumo che il comportamento non sia cambiato), questo in realtà produce class=TopBorderma i browser sono in grado di analizzarlo bene. I parser HTML sono in qualche modo indulgenti sulle virgolette degli attributi mancanti, ma questo può rompersi se hai spazi o determinati caratteri .

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

O

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

Cosa non va nel fornire le proprie citazioni

Se provi a utilizzare alcune delle solite convenzioni C # per le virgolette annidate, ti ritroverai con più virgolette di quante ti aspettassi perché Razor sta cercando di sfuggirle in modo sicuro. Per esempio:

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

Questo dovrebbe restituire <button type="button" style="border:0px">ma Razor sfugge ad ogni uscita da C # e produce in tal modo:

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

Lo vedrai solo se visualizzi la risposta sulla rete. Se usi un ispettore HTML, spesso stai effettivamente vedendo il DOM, non l'HTML grezzo. I browser analizzano l'HTML nel DOM e la rappresentazione DOM dopo l'analisi ha già alcune sottigliezze applicate. In questo caso il browser vede che non ci sono virgolette attorno al valore dell'attributo, le aggiunge:

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

Ma nell'ispettore DOM i codici dei caratteri HTML vengono visualizzati correttamente in modo da vedere effettivamente:

style=""border:0px""

In Chrome, se fai clic con il pulsante destro del mouse e selezioni Modifica HTML, torna indietro in modo da poter vedere quei cattivi codici di caratteri HTML, chiarendo che hai virgolette esterne reali e virgolette interne codificate HTML.

Quindi il problema con il tentativo di fare la citazione da solo è che Razor sfugge a questi.

Se vuoi il controllo completo dei preventivi

Usa Html.Raw per impedire l'escape delle virgolette:

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

Rende come:

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

Quanto sopra è perfettamente sicuro perché non sto emettendo alcun HTML da una variabile. L'unica variabile coinvolta è la condizione ternaria. Tuttavia, fai attenzione che quest'ultima tecnica potrebbe esporti a determinati problemi di sicurezza se si creano stringhe dai dati forniti dall'utente. Ad esempio, se hai creato un attributo dai campi di dati che hanno avuto origine dai dati forniti dall'utente, l'uso di Html.Raw significa che la stringa potrebbe contenere una fine prematura dell'attributo e del tag, quindi inizia un tag script che fa qualcosa per conto del attualmente connesso utente (possibilmente diverso dall'utente loggato). Forse hai una pagina con un elenco di tutte le immagini degli utenti e stai impostando un suggerimento come nome utente di ogni persona e un utente si chiama se stesso'/><script>$.post('changepassword.php?password=123')</script> e ora qualsiasi altro utente che visualizza questa pagina ha la propria password immediatamente modificata in una password conosciuta dall'utente malintenzionato.


Questo è un ottimo punto! E in realtà, lo rende leggibile e utilizzabile nella maggior parte delle situazioni.
Dmytro Shevchenko

Questo è quello che stavo facendo nell'esempio nella mia domanda. Grazie per una spiegazione e un esempio più elaborati. :)
tony722

1
Attenzione però agli spazi. "style = display: none;" viene visualizzato come nessuno; = "": = "" style = "display"
wmcainsh

1
Allora perché questo non funziona con: virgolette doppie magiche <span @ (true? "Class = logo-owner": string.Empty) /> Produce solo <span class = logo-owner />
rism

1
@AaronLS Sì, è esattamente come sono. Non riesco a capire come il browser (Chrome 40 / FF33.1 / IE 10) influirebbe su qualsiasi cosa poiché si tratta di markup generato dal server e, in tal caso, come mai solo quei due attributi di classe ma non per l'attributo di classe del pulsante chiedi o anche il tipo = attributi "pulsante" di tutti e tre i pulsanti. Sicuramente una cosa server IMHO dal momento che posso anche RDP in un paio di macchine virtuali Azure sparse in tutto il mondo per lo stesso risultato IE / Firefox / Chrome.
rism

12

Immagino che un modo un po 'più comodo e strutturato sia usare l'helper Html. Dal tuo punto di vista può essere simile a:

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

@* ... *@

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

Se questo modo ti sarà utile ti consiglio di definire il dizionario htmlAttrnel tuo modello in modo che la tua vista non abbia bisogno di @{ }blocchi logici (sii più chiaro).


4
-1, non consiglio mai a qualcuno di mettere logica nelle viste. Le viste dovrebbero essere responsabili solo del rendering. Aggiungi invece un esempio HtmlHelper e ti darò +1.
jgauffin

1
Per testare le cose posso usare il blocco di codice in vista: è più veloce. E la mia raccomandazione era di spostare questo blocco nel modello.
Yaschur

3
sì, ma le risposte dovrebbero mostrare le migliori pratiche e non la versione rapida e sporca che rende la manutenzione del codice un incubo.
jgauffin

@jgauffin Penso che l'helper Html qui non sia necessario. vedere la mia risposta.
gdoron supporta Monica

+1 @Yaschur La tua risposta è stimolante. Continua così. cioè. con la funzionalità di conversione esplicita C #, possiamo migliorare ulteriormente questa risposta. Non tutto il codice doveva essere modellato in un certo modo. C'è sempre un modo migliore di cui non siamo consapevoli. E alcuni progetti sono a favore dell'organizzazione del codice. L'organizzazione del codice non è per pratica concetti!
Bamboo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.