Bedingte HTML-Attribute mit Razor MVC3

100

Die Variable strCSSClass hat oft einen Wert, ist aber manchmal leer.

Ich möchte kein leeres class = "" in den HTML-Code dieses Eingabeelements aufnehmen. Wenn also strCSSClass leer ist, möchte ich das Attribut class = überhaupt nicht.

Das Folgende ist eine Möglichkeit, ein bedingtes HTML-Attribut zu erstellen:

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

Gibt es eine elegantere Möglichkeit, dies zu tun? Insbesondere eine, bei der ich der gleichen Syntax folgen könnte, die in den anderen Teilen des Elements verwendet wird: class = "@ strCSSClass"?

tony722
quelle

Antworten:

160

Sie haben es nicht von mir gehört, dem PM für Razor, aber in Razor 2 (Webseiten 2 und MVC 4) sind bedingte Attribute in Razor integriert (ab MVC 4 RC erfolgreich getestet), also können Sie einfach sagen Dinge wie dieses...

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

Wenn strCSSClass null ist, wird das Klassenattribut überhaupt nicht gerendert.

SSSHHH ... erzähl es nicht. :) :)

Erik Porter
quelle
1
Ja, du solltest meine definitiv nicht als Antwort akzeptieren. Das heißt, heute gibt es keinen saubereren Weg, dies zu tun (daher schaffen wir einen saubereren Weg, dies zu tun). Der wahrscheinlich sauberste Weg, dies zu tun, ist die Verwendung von Html.TextBox, aber das hat eine andere Reihe von weniger wünschenswerten Dingen. :( Schön, dass dir gefällt, was wir hinzufügen. :)
Erik Porter
1
Aber wie kann ich Razor-Attribute mit anderem Text kombinieren? Ich muss Folgendes machen: ... id = "[email protected]". Ich habe so etwas wie ... id = "track_2" erwartet, aber es hat die folgende Ausgabe generiert: ... id = "[email protected]" ...
Laserson
2
Sie können Razor zwingen, Code auszuwerten, indem Sie Parens darum legen. id = "track _ @ (track.ID)"
Erik Porter
1
Hinweis hinzugefügt, dass dies mit MVC 4 erfolgreich funktioniert. Wenn Sie mit MVC 3 arbeiten, siehe meine Antwort unten.
AaronLS
4
@ErikPorter BITTE NICHT MIT MEINEM HTML MESSEN !! siehe auch stackoverflow.com/questions/9234467/… dies auch für andere schlechte Verhaltensweisen
eaglestorm
126

Beachten Sie, dass Sie so etwas tun können (zumindest in MVC3):

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

Was ich für rasiermesserscharf hielt, war eigentlich der Browser. Wie Rism beim Testen mit MVC 4 hervorhob (ich habe nicht mit MVC 3 getestet, aber ich gehe davon aus, dass sich das Verhalten nicht geändert hat), führt dies tatsächlich dazu, class=TopBorderaber Browser können dies in Ordnung analysieren. Die HTML-Parser verzeihen etwas fehlende Attribut-Anführungszeichen, aber dies kann brechen, wenn Sie Leerzeichen oder bestimmte Zeichen haben .

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

ODER

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

Was geht schief, wenn Sie Ihre eigenen Angebote machen?

Wenn Sie versuchen, einige der üblichen C # -Konventionen für verschachtelte Anführungszeichen zu verwenden, erhalten Sie mehr Anführungszeichen als erwartet, da Razor versucht, ihnen sicher zu entkommen. Beispielsweise:

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

Dies sollte ausgewertet werden, <button type="button" style="border:0px">aber Razor entgeht allen Ausgaben von C # und erzeugt somit:

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

Dies wird nur angezeigt, wenn Sie die Antwort über das Netzwerk anzeigen. Wenn Sie einen HTML-Inspektor verwenden, sehen Sie häufig tatsächlich das DOM und nicht das rohe HTML. Browser analysieren HTML in das DOM, und auf die DOM-Darstellung nach dem Parsen wurden bereits einige Feinheiten angewendet. In diesem Fall sieht der Browser, dass der Attributwert keine Anführungszeichen enthält, und fügt sie hinzu:

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

Im DOM-Inspektor werden HTML-Zeichencodes jedoch ordnungsgemäß angezeigt, sodass Sie tatsächlich Folgendes sehen:

style=""border:0px""

Wenn Sie in Chrome mit der rechten Maustaste klicken und HTML bearbeiten auswählen, wird zurückgeschaltet, sodass Sie diese fiesen HTML-Zeichencodes sehen können. Dadurch wird deutlich, dass Sie echte äußere Anführungszeichen und HTML-codierte innere Anführungszeichen haben.

Das Problem beim Versuch, das Zitat selbst zu machen, ist, dass Razor diesen entgeht.

Wenn Sie die vollständige Kontrolle über Anführungszeichen wünschen

Verwenden Sie Html.Raw, um das Entweichen von Zitaten zu verhindern:

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

Rendert als:

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

Das Obige ist absolut sicher, da ich kein HTML von einer Variablen ausgebe. Die einzige Variable ist der ternäre Zustand. Beachten Sie jedoch, dass diese letzte Technik Sie bestimmten Sicherheitsproblemen aussetzen kann, wenn Sie Zeichenfolgen aus vom Benutzer bereitgestellten Daten erstellen. Wenn Sie beispielsweise ein Attribut aus Datenfeldern erstellt haben, die aus vom Benutzer bereitgestellten Daten stammen, bedeutet die Verwendung von Html.Raw, dass die Zeichenfolge ein vorzeitiges Ende des Attributs und des Tags enthalten kann. Beginnen Sie dann ein Skript-Tag, das im Namen des aktuell angemeldeten Benutzers etwas unternimmt Benutzer (möglicherweise anders als der angemeldete Benutzer). Möglicherweise haben Sie eine Seite mit einer Liste aller Benutzerbilder und legen einen Tooltip als Benutzernamen für jede Person fest, und ein Benutzer hat sich selbst benannt'/><script>$.post('changepassword.php?password=123')</script> und jetzt hat jeder andere Benutzer, der diese Seite anzeigt, sein Passwort sofort in ein Passwort geändert, das der böswillige Benutzer kennt.

AaronLS
quelle
Das ist ein sehr guter Punkt! Und tatsächlich macht es es in den meisten Situationen lesbar und verwendbar.
Dmytro Shevchenko
Das habe ich in dem Beispiel in meiner Frage gemacht. Vielen Dank für eine ausführlichere Erklärung und ein Beispiel. :)
Tony722
1
Vorsicht vor Leerzeichen. "style = display: none;" rendert als keine; = "": = "" style = "display"
wmcainsh
1
Warum funktioniert dies nicht in Bezug auf: magische doppelte Anführungszeichen <span @ (true? "Class = logo-owner": string.Empty) /> Es wird nur <span class = logo-owner />
Risma vom
1
@ AaronLS Ja genau so sind sie. Ich kann nicht verstehen, wie sich der Browser (Chrome 40 / FF33.1 / IE 10) auf irgendetwas auswirkt, da dies ein vom Server generiertes Markup ist und wenn ja, wie kommt es, dass nur diese beiden Klassenattribute, aber nicht das Klassenattribut der Ask-Schaltfläche oder sogar der Typ = "button" -Attribute aller drei Buttons. Auf jeden Fall eine Serversache, IMHO, da ich auch RDP in ein paar virtuelle Azure-Maschinen ausführen kann, die auf der ganzen Welt verteilt sind, um das gleiche Ergebnis zu erzielen. IE / Firefox / Chrome.
Rism
12

Ich denke, ein wenig bequemer und strukturierter ist die Verwendung des HTML-Helfers. Aus Ihrer Sicht kann es so aussehen:

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

@* ... *@

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

Wenn dieser Weg für Sie nützlich ist, empfehle ich, das Wörterbuch htmlAttrin Ihrem Modell zu definieren, damit Ihre Ansicht keine @{ }Logikblöcke benötigt (klarer sein).

Yaschur
quelle
4
-1, empfehlen Sie niemals jemandem, Logik in die Ansichten einzufügen. Die Ansichten sollten nur für das Rendern verantwortlich sein. Fügen Sie stattdessen ein HtmlHelper-Beispiel hinzu und ich gebe Ihnen +1.
Jgauffin
1
Um Dinge zu testen, kann ich Codeblock in der Ansicht verwenden - es ist schneller. Und meine Empfehlung war, diesen Block in ein Modell zu verschieben.
Yaschur
3
Ja, aber die Antworten sollten die beste Vorgehensweise zeigen und nicht die schnelle und schmutzige Version, die die Codepflege zu einem Albtraum macht.
Jgauffin
@jgauffin Ich denke, HTML-Helfer hier ist unnötig. siehe meine Antwort.
Gdoron unterstützt Monica
+1 @Yaschur Ihre Antwort ist inspirierend. Mach weiter so. dh. Mit der expliziten C # -Konvertierungsfunktion können wir diese Antwort noch weiter verbessern. Nicht der gesamte Code musste auf eine bestimmte Weise geformt werden. Es gibt immer einen besseren Weg, den wir nicht kennen. Und einige Projekte befürworten die Code-Organisation. Code-Organisation sind in der Praxis keine Konzepte!
Bambus