Como adicionar uma segunda classe css com um valor condicional no MVC 4

149

Embora a Microsoft tenha criado uma renderização automagica de atributos html no MVC4, demorei bastante tempo para descobrir como renderizar uma segunda classe css em um elemento, com base em uma expressão condicional do razor. Eu gostaria de compartilhar com você.

Com base na propriedade model @ Model.Details, quero mostrar ou ocultar um item da lista. Se houver detalhes, uma div deve ser mostrada; caso contrário, ela deve estar oculta. Usando o jQuery, tudo o que preciso fazer é adicionar um show de classe ou ocultar, respectivamente. Para outros fins, também quero adicionar outra classe, "detalhes". Portanto, minha marcação deve ser:

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

Abaixo, mostro algumas tentativas com falha (marcação resultante, assumindo que não há detalhes).

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

vai tornar este: <div class="details" hide="">.

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

vai tornar este: <div class=""details" hide&quot;="">.

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

vai tornar este: <div class="'details" hide&#39;="">.

Nenhuma dessas marcações está correta.

R. Schreurs
fonte
Todas as suas primeiras soluções teria trabalhado se enrolou-as em uma nova instância do MvcHtmlString ou usado Html.Raw
Kyle

Respostas:

301

Eu acredito que ainda pode haver uma lógica válida nas visualizações. Mas para esse tipo de coisa que eu concordo com o @BigMike, é melhor colocado no modelo. Dito isto, o problema pode ser resolvido de três maneiras:

Sua resposta (supondo que isso funcione, eu não tentei isso):

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

Segunda opçao:

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

Terceira opção:

<div class="@("details " + (Model.Details.Count>0 ? "show" : "hide"))">
von v.
fonte
2
Aceitei isso como resposta, pois oferece mais opções do que as minhas.
R. Schreurs
18
A segunda opção causa o erroThe "div" element was not closed
intrepidis
6
Claro que, como está escrito aqui, não é o código completo, mas a parte do código em questão. Quem sabe quantos outros elementos estão no div;)
von v.
Não funcionou para mim. Eu obtive este erro #'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
Como o seu problema está relacionado à pergunta postada?
von v.
69

Este:

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

irá renderizar isso:

    <div class="details hide">

e é a marcação que eu quero.

R. Schreurs
fonte
1
Não gosto de ter lógica nas visualizações, mesmo que seja lógica trivial, prefiro usar um objeto ModelView com o método getDetailClass ().
BigMike 29/03
29
Pessoalmente, prefiro a lógica trivial, ter um método getDetailCssClass significa que seu Model está ciente de sua View, detalhando essa abstração. Eu adicionaria um método HasDetails ao Model para reduzir a lógica necessária na visualização e, em seguida, deixaria a lógica da classe css na visualização, o que significa que você não precisa criar lixo na visualização @Model.Details.Count > 0. por exemplo<div class="details @(@Model.HasDetails ? "show" : "hide")">
Chris Diver
26

Você pode adicionar propriedades ao seu modelo da seguinte maneira:

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

e sua visualização será mais simples e não conterá lógica alguma:

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

Isso funcionará mesmo com muitas classes e não renderizará a classe se for nulo:

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

com 2 propriedades não nulas renderizará:

    <div class="class1 class2"/>

se class1 for nulo

    <div class=" class2"/>
sincronizado
fonte
11
Eu acho que é melhor deixar a visão definir coisas como as classes css. Lembre-se que o ponto de vista deve ser capaz de ser deply modificado (ou mesmo substituído) sem afectar o Model View
tobiak777
1
Embora eu concorde com o reddy em geral, pode haver casos em que isso pode ser justificado da maneira que a sincronização diz. Eu fiz exatamente assim. No meu caso, estou contando com um objeto ViewModel cheio de informações para renderizar a exibição, não é apenas um objeto de dados.
Gonzalo Méndez
1
Eu usaria assim se houvesse mais de 2 resultados. Por exemplo, para 5 classes possíveis. Do que seria confuso mantê-lo à vista.
Mateusz Migała 19/04/19
1
A vista é o lugar certo. Formate-o bem como atribuições de variáveis ​​em um bloco de código e não será confuso.
precisa
3

Você pode usar a função String.Format para adicionar a segunda classe com base na condição:

<div class="@String.Format("details {0}", Details.Count > 0 ? "show" : "hide")">
Chetan Gaonkar
fonte