Simple_form: input_html options for each item in a collection

Created on 17 Feb 2011  路  52Comments  路  Source: heartcombo/simple_form

It would be useful to be able to add a css class or data attribute to each item in a collection, based on a lambda.

(as you can currently do with :label_method + :value_method)

Feature request

Most helpful comment

Forgive my ignorance but could it have something to do with this? See the bottom comment

http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_for_select#1030-helpers-using-options-for-select

options_for_select([["Dollar", "$", {:class=>"bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]])

Edit just realised that it's only collection_select that matters here

Edit 2 incase anyone else reads this thread. This is working perfectly for my needs using pivotal's changes (thanks!)

<%= f.input :project, :collection => Proc.new{ Project.all.map{ |p| [p.name, p.id, :class => "project-#{p.id}"] } } %>

All 52 comments

Perhaps, do you have any specific use case?

A country select list, certain countries in the list are VAT eligible, the lambda compares items against another array and adds a data-attribute if there's a match.

This makes, for example, showing / hiding other parts of the form based on the selection very easy with JavaScript.

I see your point. The problem with the select list is that it just delegates to Rails collecion_select helper, and we do not have control over the select options being created, given they delegate to options_from_collection_for_select and so on. Basically, this is not in SimpleForm hands, unless we recreate this helper entirely.

I'm unable to work on this right now, but I'd be happy to receive a pull request if you want to do some work on it =). Thanks.

This is basically a fundamental feature based on experience in last 3 projects. I considered making a patch myself recently but as it's for some reason outside of simple form scope I'll monkey-patch it, I bet most people will do this - which is bad. =S

Test + possible solution for this here:

https://github.com/pivotal-casebook/simple_form/commit/f134b1c606952040d90d0bbbbe7deff7f0dc5f61

Not sure if a proc is the greatest way to solve this but like carlos said part of the problem is collection_select gives you no control over these things but a select tag will provided you do all the work with your own options.

May submit a pull request but I think documentation should be added along with some clarity around what to do if you provide other options that would be ignored (such as :label_method etc etc)

@pivotal-casebook: I'm not sure this is very good solution (sorry, not trying to be rude), a per-item-proc would make so much more sense - but yes it requires patching Rails form helpers. My personal opinion is that Rails core form helpers are kind of useless anyway - why are we all using simple_form or formtastic to start with? Don't know anyone relying on the core ones - so overriding the core ones probably is a must either way.

@pivotal-casebook although your solution is simple (I really haven't thought about it), I have to agree with @grimen that a per-item-proc seems more reasonable. I would not like to recreate the entire collection_select feature, but I can't see other way =(

grimen I've just arrived at this dilemma too
http://groups.google.com/group/plataformatec-simpleform/browse_thread/thread/286adefdf4656b05

If you have any done any work on it so far or monkey patching etc I'd love to see.

Thanks

Forgive my ignorance but could it have something to do with this? See the bottom comment

http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_for_select#1030-helpers-using-options-for-select

options_for_select([["Dollar", "$", {:class=>"bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]])

Edit just realised that it's only collection_select that matters here

Edit 2 incase anyone else reads this thread. This is working perfectly for my needs using pivotal's changes (thanks!)

<%= f.input :project, :collection => Proc.new{ Project.all.map{ |p| [p.name, p.id, :class => "project-#{p.id}"] } } %>

Yes, you're completely right! This was added to Rails 3, you're able to give a hash of options to the collection in the array form. So giving a collection like this (from SF test suite):

:collection => [['Jose', 'jose', { :class => "bar" }], ['Carlos', 'carlos', { :id => "baz" }]]

Would output a select like this:

<select class="select required" id="user_name" name="user[name]">
  <option value=""></option>
  <option value="Jose" class="bar">Jose</option>
  <option value="Carlos" id="baz">Carlos</option>
</select>

It means you can give any options to the items in the collection, and we won't need to do any work for that =). Thanks mate.

Btw, just saw your edit2 example, you shouldn't need the patch + use Proc.new, just giving the collection with Project.all.map as you did should work fine.

Awesome! Ah yes of course, it works just with map like you said. Thanks Carlos

Hmm...interesting, I've totally missed that was added to Rails 3. Great, this means I can nuke some ugly code then!

Not sure if I completely misunderstood you guys conclusions, but I run Rails 3.0.5 and I now got back to this "problem" in a project and I tried this example:

payment.input :method, :as => :radio, :collection => [['Bar', 'bar', {:class => "bar"}], ['Baz', 'baz', {:id => "baz"}]]

...renders:

http://pastie.org/1745868 (forgot how to escape HTML in GH-comments :P)

How did you manage to get a valid output? Are you guys running 3.1.0.beta?

@grimen sorry mate, I guess I should've explained it better. This implementation only works for selects as it's done inside Rails form options helpers. SimpleForm collection helpers (radio / check boxes) do not handle this third option, although we could think about implementing it somehow. If you think it'd be useful, I guess we should open another issue explaining how it'd be and close this one. What do you think?

@carlosantoniodasilva Ah, I see - yes I think my assumption says that this shoould work if it is expected to work for selects. Would love to discuss a solution on this, though I need to refresh my memory on the simple_form codebase - haven't peeped it in long time now. :)

Just noted in my app (and it is visible on the example above):

  :collection => [['Jose', 'jose', { :class => "bar" }], ['Carlos', 'carlos', { :id => "baz" }]]

Would output a select like this:

  <select class="select required" id="user_name" name="user[name]">
    <option value=""></option>
    <option value="Jose" class="bar">Jose</option>
    <option value="Carlos" id="baz">Carlos</option>
  </select>

The VALUE for each option is incorrectly taken from first array member, not the second (you can see it is capitalized...). Vanilla Rails 3 options_for_select works OK.

With relation to the previous post. I'm finding this behaviour too. I tried to find a reason in the code but got a bit lost. Would someone be able to provide some insight into why collection options structured as above don't allow for the value to be defined in the second array element?

@brendon Actually, I've never used it this way, maybe it's a SimpleForm issue. Have you tried using only :collection_select with a collection having such options, to see if it works fine? If it works, we can look at SimpleForm to find out where the issue is. Thanks.

Thanks Carlos,

From my experiments, I think it has something to do with the value_method and input_method defaults. Normally :first and :last I think they may be defaulting to :first and :first because the last item in this case is a Hash. I tried setting it to :first and :second and that worked, but it then ignored my Hash (i.e. didn't pass it through as an options hash). That's about as far as I got.

I was trying to find if there was a way to manually pass the select html straight from the rails helper into SimpleForm, and from what you say it sounds like :collection_select is the way to do this? I'll give it a go when I get to work and see how that goes. If it works, I can't see any reason why SimpleForm needs to change :D

Have a great day!

Ah, I see. I tried calling collection_select and it had the same incorrect results as through simple_form when I define the value_method and text_method.

Using options_for_select works properly though. Does simple_form use this in any way?

Is there a way to supply pre-generated options from options_for_select to the simple_form input helper? :)

@brendon well, I'm not sure it's possible to use options_for_select with
collection_select, I don't remember using it anywhere. So I don't think
there is a way to supply the generated options to the SF input helper right
now.

On Tue, May 10, 2011 at 6:59 PM, brendon <
[email protected]>wrote:

Ah, I see. I tried calling collection_select and it had the same incorrect
results as through simple_form when I define the value_method and
text_method.

Using options_for_select works properly though. Does simple_form use this
in any way?

Is there a way to supply pre-generated options from options_for_select to
the simple_form input helper? :)

Reply to this email directly or view it on GitHub:
https://github.com/plataformatec/simple_form/issues/188#comment_1133802

At.
Carlos A. da Silva

Thanks Carlos :) In lieu of that, I'll just have to use the standard rails select helper. The only part that I get stuck on with that is generating the wrapper div that has all the handy classnames for the input. Is there a way of generating that without having to render a simple_form input, or should I just manually put it in? Creating the label, hint, and error outputs separately works well still :)

You can use the input helper with block to do this. With a block the input helper will render only the wrapper, label, hint and error without input. e.g.:

<%= f.input :name do %>
  <%= f.select :your_method %>
<% end %>

Yup, nice one @rafaelfranca. I guess it's the easier way.

On Tue, May 10, 2011 at 9:32 PM, rafaelfranca <
[email protected]>wrote:

You can use the input helper with block to do this. With a block the input
helper will render only the wrapper, label, hint and error without input.
e.g.:

<%= f.input :name do %>
 <%= f.select :your_method %>
<% end %>

Reply to this email directly or view it on GitHub:
https://github.com/plataformatec/simple_form/issues/188#comment_1134910

At.
Carlos A. da Silva

Thanks Rafael! :) I knew there must have been a block way of doing it but couldn't find it mentioned anywhere :D

It's working great now, thank you both for your help :)

Yeah... it is poorly documented. Could you help us and improve the documentation of this feature? :heart:

I sure can :) Would a wiki post do? or do you want it in the readme? :)

I think that the README is the better place.
Most of users don't look at the wiki.
Would be great if the README had informations about the block input helper and how the rails helper can be used with it.

Roger that. I'll look at adding that in and send through a pull request.
I'll try to explain it as best I can so feel free to fix it up if I bungle
it :)

On Wed, May 11, 2011 at 1:39 PM, rafaelfranca <
[email protected]>wrote:

I think that the README is the better place.
Most of users don't look at the wiki.
Would be great if the README had informations about the block input helper
and how the rails helper can be used with it.

Reply to this email directly or view it on GitHub:
https://github.com/plataformatec/simple_form/issues/188#comment_1135115

I've submitted a pull request with the updated documentation. I think this issue could probably be closed as a workaround now exists, unless someone wants to actually implement this behaviour in SimpleForm too? :)

Thanks mate! The pull request was applied and I'm closing this issue

Cool! I think that's my first pull request that has been accepted! :D

Cheers,

Brendon

On Wed, May 25, 2011 at 1:39 PM, rafaelfranca <
[email protected]>wrote:

Thanks mate! The pull request was applied and I'm closing this issue

Reply to this email directly or view it on GitHub:
https://github.com/plataformatec/simple_form/issues/188#comment_1232630

:D, feel free to send us more pull requests.

Lol :) Will do :)

On Wed, May 25, 2011 at 1:53 PM, rafaelfranca <
[email protected]>wrote:

:D, feel free to send us more pull requests.

Reply to this email directly or view it on GitHub:
https://github.com/plataformatec/simple_form/issues/188#comment_1232674

Hey, sorry to revive this old thread, but I'm curious as to why this is not working:

f.input :type, collection: [ "Type 1", "type_1", class: "type_1_class" ]

The value should be type_1, but is Type 1. Why hasn't this been fixed? Or maybe I'm doing something wrong.

@niuage I don't think passing a third option as html options for each option value works with collection select in Rails 3-2, I think this support was only added to Rails 4 - which should work with SimpleForm master / 3.0.0.beta1.

For achieving that you should give a block to the f.input helper and call f.select (the rails helper) passing the correct options. Something like that I guess:

f.input :type, as: :select do
  f.select :type, [ "Type 1", "type_1", class: "type_1_class" ]
end

Thanks, that's what I ended up doing, after posting on SO, and finding one of your posts. Glad that it will "fixed" in rails 4. This solution is not that bad though.

I believe it's not fixed in Rails4 :crying_cat_face:
I think simple_form should override options_from_collection_for_select and provide :option_html_method

Regardless options_from_collection_for_select should be fixed to accept hash with html_parameters. Or am I missing the point here?

If the block syntax works, so I don't think we should override this method.

f.input :type, as: :select do
  f.select :type, [ "Type 1", "type_1", class: "type_1_class" ]
end

I agree. But people keep stepping on this rack. This issue is about simple_form and it could be described this way:
_If one may use this code:_

f.input :foo, collection: [['bar', 1], ['baz', 2]]

_why can't she use this:_

f.input :foo, collection: [['bar', 1], ['baz', 2, {class: :cool, disabled: :disabled]]

which would render:

<select>
  <option value="1">bar</option>
  <option value="baz" class="cool" disabled="disabled">baz</option>
</select>
# look at 'value' attribute

It looks like a bug even if it's rails bug. If you insist this form is not supported then simple_form should pass :value_method => :second to silently ignore the attributes hash. That would be a least surprise.

Alright! We need to fix this

:thumbsup:

since https://github.com/rails/rails/pull/10173 was merged I think it should work with current rails master. Not sure if it'll be in Rails 4.0 release (@rafaelfranca will it be?) but I'm closing this since it fixed in rails.

I'm wondering how it works with grouped_select.

@tonytonyjan Actually it works the same way. I've just added a test for this feature. I hope this will help.

@nashby Thank you, it helps = )

Hi, this does not work properly. As @kupinus mentioned 2 years ago it puts wrong data to the value attribute.

When I use [["Label", 1, class => "test"]] I am expecting to have:

<option value="1" class="test">Label</option>

when actually get:

<option value="Label" class="test">Label</option>

In lib/simple_form/inputs/collection_input.rb

if collection_translated || collection_classes.include?(Array)
  { :label => :first, :value => :last }

Should become:

if collection_translated || collection_classes.include?(Array)
  { :label => :first, :value => :second }

:last does not work because there are more than 2 elements in array and the last one is a hash.

Hmm, that actually breaks the desired functionality with option's params.

UPD: would be good to be able to pass [["Label", { :value => "1", :class => "test" }]] this seems logically correct to me, since we're passing other option params in a hash.

@heaven well, it's :value => :second in master branch and your first example should work as expected.

Any updates on this? I need to conditionally provide data attributes based upon the current relationship, but it doesn't seem possible without essentially iterating & outputting the proper HTML manually.

@mhuggins tell us about your rails/simple form versions please.

Was this page helpful?
0 / 5 - 0 ratings