web-dev-qa-db-fra.com

Comment ajouter des attributs HTML pour sélectionner des options avec Simple Form Rails?

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>

@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!

22
YWCA Hello

Cela semble être la bonne façon de faire ceci:

Champ de sélection de l'association personnalisée Rails Simple Form

0
YWCA Hello

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 %>
18
Blair Anderson

forme simple seulement:

= f.input :group, @groups.map{|l| [l[0], l[1], {data: {type: l[2]}}]}

4
Bruno Porto

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.

1
Markus