Qual é uma maneira elegante de adicionar condicionalmente uma classe a um elemento HTML em uma visualização?

103

Ocasionalmente, tenho que adicionar uma classe a um elemento html com base em uma condição. O problema é que não consigo descobrir uma maneira limpa de fazer isso. Aqui está um exemplo do que experimentei:

<div <%= if @status = 'success'; "class='ok'"; end %>>
   some message here
</div>

OU

<% if @status == 'success' %>
   <div class='success'>
<% else %>
   <div>
<% end %>
   some message here
</div>

Eu não gosto da primeira abordagem porque ela parece lotada e é difícil de ler. Eu não gosto da segunda abordagem porque o aninhamento está bagunçado. Seria bom colocá-lo no modelo, (algo como @status.css_class), mas isso não pertence lá. O que a maioria das pessoas faz?

Ryeguy
fonte

Respostas:

141

Eu uso a primeira maneira, mas com uma sintaxe um pouco mais sucinta:

<div class="<%= 'ok' if @status == 'success' %>">

Embora normalmente você deva representar sucesso com booleano trueou um ID de registro numérico e falha com booleano falseou nil. Dessa forma, você pode apenas testar sua variável:

<div class="<%= 'ok' if @success %>">

Uma segunda forma usando o ?:operador ternário é útil se você deseja escolher entre duas classes:

<div class="<%= @success ? 'good' : 'bad' %>">

Finalmente, você pode usar os ajudantes de etiqueta de registro do Rail , como div_for, que definirá automaticamente sua ID e classe com base no registro que você fornecer. Dado um Personcom id 47:

# <div id="person_47" class="person good">
<% div_for @person, class: (@success ? 'good' : 'bad') do %>
<% end %>
meagar
fonte
@Anurag, verifique isto api.rubyonrails.org/classes/ActionController/… . Coisas muito legais.
maček
obrigado pelo link @macek. isso é muito semelhante a como eu crio elementos no MooTools :) limpo e arrumado
Anurag
2
Melhor resposta: evite toda a bagunça e mude suas visualizações para HAML .
meagar
2
Ou, melhor ainda, para SLIM
Dr.Strangelove
4
@ Dr.Strangelove, você poderia dar um exemplo de como SLIM ou HAML lidaria com classes condicionais de forma mais elegante? E no caso de várias classes condicionais?
Brendon Muir
18

Evitando lógica nas visualizações

O problema com a abordagem padrão é que ela requer lógica na forma de ifdeclarações ou ternários na visualização. Se você tiver várias classes CSS condicionais misturadas com classes padrão, precisará colocar essa lógica em uma interpolação de string ou tag ERB.

Esta é uma abordagem atualizada que evita colocar qualquer lógica nas visualizações:

<div class="<%= class_string(ok: @success) %>">
   some message here
</div>

class_string método

O class_stringauxiliar recebe um hash com pares de chave / valor consistindo em strings de nome de classe CSS e valores booleanos . O resultado do método é uma string de classes onde o valor booleano é avaliado como verdadeiro.

Uso de amostra

class_names(foo: true, bar: false, baz: some_truthy_variable)
# => "foo baz"

Outros casos de uso

Este helper pode ser usado dentro de ERBtags ou com helpers Rails como link_to.

<div class="<%= class_string(ok: @success) %>">
   some message here
</div>

<% div_for @person, class: class_string(ok: @success) do %>
<% end %>

<% link_to "Hello", root_path, class: class_string(ok: @success) do %>
<% end %>

Classes ou classes

Para casos de uso em que um ternário seria necessário (por exemplo @success ? 'good' : 'bad'), passe uma matriz onde o primeiro elemento é a classe para truee o outro é parafalse

<div class="<%= [:good, :bad] => @success %>">

Inspirado por React

Essa técnica é inspirada por um add-on chamado classNames(anteriormente conhecido como classSet) da estrutura de Reactfront-end do Facebook .

Usando em seus projetos Rails

A partir de agora, a class_namesfunção não existe no Rails, mas este artigo mostra como adicioná-la ou implementá-la em seus projetos.

Carlos Ramirez III
fonte
2

Você também pode usar o helper content_for, especialmente se o DOM estiver localizado em um layout e você quiser definir a classe css dependendo do carregamento parcial.

No layout:

%div{class: content_for?(:css_class) ? yield(:css_class) : ''}

Na parcial:

- content_for :css_class do
    my_specific_class

É isso.

acmoune
fonte