J'ai besoin d'ajouter un attribut HTML personnalisé à chaque option
pour un contrôle select
. J'utilise simple_form dans Rails. Est-ce que quelqu'un sait comment faire ça? L'attribut sera utilisé par le JS côté client.
Par exemple, je veux faire quelque chose comme ceci:
<%= f.input :group, collection: @groups, option_html: { data-type: lambda { |g| g[2] } } %>
Qui produirait (simplifié):
<select>
<option value="1" data-type="primary">First Group</option>
<option value="2" data-type="secondary">Second Group</option>
<option value="3" data-type="secondary">Third Group</option>
</select>
Où @groups
pourrait ressembler à ceci:
[
['First Group', 1, 'primary'],
['Second Group', 2, 'secondary'],
['Third Group', 3, 'secondary']
]
En espérant éviter d'avoir à créer un contrôle/wrapper personnalisé. Merci!
Cela semble être la bonne façon de faire ceci:
Champ de sélection de l'association personnalisée Rails Simple Form
Tu es proche! Le moyen le plus simple n’est pas d’utiliser simple_form ici. voici la documentation simple_form
<% options = @group.map { |g| [g.name, g.id, {'data-type' => g.group_type}] } %>
<%= f.input :group, label: 'Group' do %>
<%= f.select :group, options, include_blank: 'Select a Group', class: 'form-control' %>
<% end %>
Pour votre code exact ce serait:
<% options = @group.map { |g| [g[0], g[1], {'data-type' => g[2]}] } %>
<%= f.input :group, label: 'Group' do %>
<%= f.select :group, options, include_blank: 'Select a Group', class: 'form-control' %>
<% end %>
forme simple seulement:
= f.input :group, @groups.map{|l| [l[0], l[1], {data: {type: l[2]}}]}
Un (petit) inconvénient avec la méthode f.input do end
est que toutes les options HTML d'entrée par défaut (telles que les classes required
ou optional
du formulaire simple ou l'attribut required
) et les options par défaut (comme b.use :input, class: 'input-element'
) sont manquantes lors du passage d'un bloc à f.input
, tldr : l'entrée n'est pas décorée .
Si vous comptez sur ces classes et attributs supplémentaires, vous devrez les transmettre manuellement (pas à sec).
Pour surmonter ce problème, j'ai créé une entrée personnalisée pour mes sélections spéciales afin de pouvoir définir le corps de ma sélection comme je le souhaite (les balises <option>
), mais la sélection est décorée comme d'habitude:
# app/inputs/select_container_input.rb
class SelectContainerInput < SimpleForm::Inputs::Base
def input(wrapper_options)
options_html = input_options.delete(:options_html)
# since we pass our options by our self (and have to select the correct
# option), set `selected` to `''` to prevent Rails calling
# `object.send(attribute_name)` only to set `selected` which is not used.
input_options[:selected] = ''
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
@builder.select attribute_name, nil, input_options, merged_input_options do
options_html
end
end
end
Appelez-le simplement comme ceci:
<% options_html = capture do %>
<option>bla</option>
<% end %>
<%= f.input :attribute, as: :select_container, options_html: options_html %>
Le options_html
est une solution de contournement, car en réalité, il serait plus facile de passer un bloc à notre entrée personnalisée:
<%= f.input :attribute, as: :select_container do %>
<option>bla</option>
<% end %>
Mais en raison de la manière dont SimpleForm :: FormBuilder # def_input fonctionne, le bloc s’emporte avant même que le code ne touche les entrées. Donc pas question de refactoriser simple_form.
Dans l’ensemble, cela résout le problème avec un code un peu plus bruyant dans vos vues pour vos sélections spéciales.