Comment ajouter des attributs HTML pour sélectionner des options avec des Rails de formulaire simples?
J'ai besoin d'ajouter un attribut HTML pour chaque option
pour un select
contrôler. J'utilise simple_form dans Rails. Personne ne sait comment faire cela? L'attribut sera consommé par 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 à faire un contrôle/wrapper personnalisé. Merci!
4 réponses
Tu es proche! le moyen le plus simple est de ne pas 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 %>
Simple-seulement sous la forme:
= f.input :group, @groups.map{|l| [l[0], l[1], {data: {type: l[2]}}]}
Un (petit) inconvénient en utilisant la méthode f.input do end
est que toutes les options html d'entrée par défaut (comme les classes required
ou optional
ou l'attribut required
) et toutes les options par défaut (comme b.use :input, class: 'input-element'
) sont manquantes lors du simple 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 cela, j'ai créé une entrée personnalisée pour mes sélections spéciales, afin que je puisse définissez le corps de ma sélection comme je veux (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 il serait en fait 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 façon dont SimpleForm::FormBuilder#def_input fonctionne, le bloc est emporté avant que le code ne touche même les entrées. Donc pas moyen sans refactoring simple_form.
Tout dans tout cela résout le problème avec un peu de code bruyant supplémentaire dans vos vues pour vos sélections spéciales.
Cela semble être la bonne façon de faire:
Rails simple Form association personnalisée sélectionnez le champ