Jak dodać drugą klasę CSS z wartością warunkową w Razor MVC 4

149

Podczas gdy Microsoft stworzył pewne automagiczne renderowanie atrybutów HTML w maszynce do golenia MVC4, zajęło mi trochę czasu, zanim dowiedziałem się, jak wyrenderować drugą klasę css na elemencie, w oparciu o warunkowe wyrażenie maszynki do golenia. Chciałbym się z wami tym podzielić.

Opierając się na właściwości modelu @ Model.Details, chcę pokazać lub ukryć element listy. Jeśli istnieją szczegóły, należy wyświetlić element div, w przeciwnym razie powinien zostać ukryty. Korzystając z jQuery, wszystko, co muszę zrobić, to dodać odpowiednio klasę show lub hide. Z innych powodów chcę również dodać kolejną klasę, „szczegóły”. Tak więc moja marża powinna wynosić:

<div class="details show">[Details]</div> lub <div class="details hide">[Details]</div>

Poniżej przedstawiam kilka nieudanych prób (wynikający z marży przy założeniu, że nie ma szczegółów).

To: <div @(@Model.Details.Count > 0 ? "class=details show" : "class=details hide")>,

uczyni to: <div class="details" hide="">.

To: <div @(@Model.Details.Count > 0 ? "class=\"details show\"" : "class=\"details hide\"")> .

uczyni to: <div class=""details" hide&quot;="">.

To: <div @(@Model.Details.Count > 0 ? "class='details show'" : "class='details hide'")>

uczyni to: <div class="'details" hide&#39;="">.

Żadne z nich nie są poprawnymi marżami.

R. Schreurs
źródło
Wszystkie twoje pierwsze rozwiązania zadziałałyby, gdybyś zapakował je w nową instancję MvcHtmlString lub użył Html.Raw
Kyle.

Odpowiedzi:

301

Uważam, że w poglądach wciąż może istnieć i ważna logika. Ale na tego typu rzeczy zgadzam się z @BigMike, lepiej jest umieścić go na modelu. Powiedziawszy, że problem można rozwiązać na trzy sposoby:

Twoja odpowiedź (zakładając, że to działa, nie próbowałem tego):

<div class="details @(@Model.Details.Count > 0 ? "show" : "hide")">

Druga opcja:

@if (Model.Details.Count > 0) {
    <div class="details show">
}
else {
    <div class="details hide">
}

Trzecia opcja:

<div class="@("details " + (Model.Details.Count>0 ? "show" : "hide"))">
von v.
źródło
2
Przyjąłem to jako odpowiedź, ponieważ oferuje więcej opcji niż moja.
R. Schreurs
18
Druga opcja powoduje błądThe "div" element was not closed
intrepidis
6
Oczywiście będzie tak, ponieważ to, co tu napisano, nie jest pełnym kodem, ale raczej jego częścią, o której mowa. Kto wie, ile innych elementów jest w div;)
von v.
Nie działa dla mnie. Mam ten błąd'ClubsModel' does not contain a definition for 'ClubsFilter' and no extension method 'ClubsFilter' accepting a first argument of type 'ClubsModel' could be found (are you missing a using directive or an assembly reference?)
Martin Erlic
Jaki jest związek Twojego problemu z opublikowanym pytaniem?
von v.
69

To:

    <div class="details @(Model.Details.Count > 0 ? "show" : "hide")">

wyrenderuje to:

    <div class="details hide">

i to jest narzut, którego chcę.

R. Schreurs
źródło
1
Nie lubię mieć logiki w widokach, nawet jeśli jest to logika trywialna, wolę używać obiektu ModelView z metodą getDetailClass ().
BigMike
29
Osobiście wolę trywialną logikę, posiadanie metody getDetailCssClass oznacza, że ​​Twój Model jest świadomy Twojego Widoku, przełamując tę ​​abstrakcję. Dodałbym metodę HasDetails do Modelu, aby zmniejszyć logikę wymaganą w widoku, a następnie pozostawiłbym logikę klasy css w widoku, co oznacza, że ​​nie musisz zaśmiecać widoku@Model.Details.Count > 0 . np.<div class="details @(@Model.HasDetails ? "show" : "hide")">
Chris Diver
26

Możesz dodać właściwość do swojego modelu w następujący sposób:

    public string DetailsClass { get { return Details.Count > 0 ? "show" : "hide" } }

a wtedy twój widok będzie prostszy i nie będzie zawierał żadnej logiki:

    <div class="details @Model.DetailsClass"/>

To zadziała nawet z wieloma klasami i nie wyrenderuje klasy, jeśli jest pusta:

    <div class="@Model.Class1 @Model.Class2"/>

z 2 niezerowymi właściwościami wyrenderuje:

    <div class="class1 class2"/>

jeśli class1 ma wartość null

    <div class=" class2"/>
zsynchronizowane
źródło
11
Myślę, że lepiej jest pozwolić widokowi zdefiniować takie rzeczy, jak klasy css. Pamiętaj, że widok powinien móc być głęboko modyfikowany (lub nawet zastępowany) bez wpływu na model widoku
tobiak777
1
Chociaż ogólnie zgadzam się z reddy, mogą wystąpić przypadki, w których można to zrobić tak, jak mówi syned. Zrobiłem to dokładnie w ten sposób. W moim przypadku polegam na obiekcie ViewModel pełnym informacji do renderowania widoku, nie jest to tylko obiekt danych.
Gonzalo Méndez
1
Użyłbym tego w ten sposób, gdyby było więcej niż 2 wyniki. Na przykład na 5 możliwych zajęć. Niż byłoby niechlujnie trzymać to na widoku.
Mateusz Migała
1
Widok jest we właściwym miejscu. Sformatuj go ładnie jako przypisania zmiennych w bloku kodu i nie będzie bałaganu.
Tom Blodget
3

Możesz użyć funkcji String.Format, aby dodać drugą klasę na podstawie warunku:

<div class="@String.Format("details {0}", Details.Count > 0 ? "show" : "hide")">
Chetan Gaonkar
źródło