< Return to Blog

HOWTO: Chosen.js for Multiple Select fields with Search in Autoglym Professional

I didn't have much time to build this feature, and hit the interweb for multi-select options and stumbled on the fantastic Chosen.js. Since I was working on Rails 3.2.x app at the time, I went with https://rails-assets.org/

source 'https://rails-assets.org' do
  gem 'rails-assets-chosen'
end

...and simply loaded chosen into the JS and CSS Sprockets manifests.

Since I was in a hurry, I kept things simple, and my JS looked like

    $('.chosen-select').chosen({});
    $('.chosen-select').on('change', function(e, p) {
      var interests = $(this).val();
      $('.franchisee-interests').val(interests);
    });

Also, rather than going with a full-blown ERB approach, when working with JS I find it easier to go with straight markup at times, although there's nothing stopping one from converting this example into ERB.

Before adding in chosen, I had one of the form helpers populate a normal select field. I just used the Chrome dev tools to copy the DOM node and replace it with pure markup from the node I copied. I didn't have to type much of this, it was ultimately generated by Rails' form helper boilerplate.

          <li class="select input required" id="franchisee_contact_interest_areas_input">
            <label class="label" for="franchisee_contact_interest_areas">Area of interest<abbr title="required">*</abbr></label>
            <select id="franchisee_contact_interest_areas" name="interest_areas_list" data-placeholder="Your Areas of Interest" class="chosen-select" multiple>
              <option value=""></option>

              <% @form_object.class::INTEREST_AREAS.each do |area, areas| %>
                <optgroup label="<%= area %>">
                  <% areas.each do |option| %>
                    <%
                      selected = nil
                      if params[:franchisee_contact] && params[:franchisee_contact][:interest_areas]
                        areas = params[:franchisee_contact][:interest_areas].split(',')
                        selected = "selected" if areas.any? && areas.include?(option)
                      end
                    %>
                    <option <%= selected %>><%= option %></option>
                  <% end %>
                </optgroup>
              <% end %>

            </select>
          </li>
          <%= hidden_field_tag "franchisee_contact[interest_areas]", nil, class: "franchisee-interests" %>

The approach I took was to basically throw-away the param interest_areas_list sent across, yet rely on the information sent via the hidden field. I did some additional processing within the controller's create action, but that's expected.