Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use select2-rails with simple_form?

This select2 jquery library looks awesome. There is a Rails gem but it is very light on the documentation. I would like to generate a simple multiple drop-down menu, using autocomplete. How do I do that?

This is my simple_form_for call:

<%= f.input_field :neighborhood_names, url: autocomplete_neighborhood_name_searches_path, as: :autocomplete, data: { delimiter: ',', placeholder: "Where do you want to live?"}, multiple: true, id: "selectWhereToLive", class: "span8" %>

I have successfully installed the select2-rails gem, but not quite sure how to get it working.

I add this to my home.js.coffeefile:

jQuery ->
    $('#selectWhereToLive').select2()

And am getting this error:

Uncaught query function not defined for Select2 selectWhereToLive 

Thoughts?

Edit 1:

The above simple_form_for call is producing this HTML:

<input class="autocomplete optional span8" data-autocomplete="/searches/autocomplete_neighborhood_name" data-delimiter="," data-placeholder="Where do you want to live?" id="selectWhereToLive" multiple="multiple" name="search[neighborhood_names][]" size="30" type="text" url="/searches/autocomplete_neighborhood_name" value="" />

Indicating that the id attribute is being properly set.

Edit 2 - Updated

As @moonfly suggested, I tried adding as: :select to the f.input_field - both with as: :autocomplete included and not included.

The resulting HTML without as: :autocomplete was this:

<input name="search[neighborhood_names][]" type="hidden" value="" /><select class="select optional span8" data-delimiter="," data-placeholder="Where do you want to live?" id="selectWhereToLive" multiple="multiple" name="search[neighborhood_names][]" url="/searches/autocomplete_neighborhood_name"><option value="true">Yes</option>
<option value="false">No</option></select>

It pre-populates 2 option values 'Yes' and 'No'. Not quite sure why, but that is what it does.

Update

So I had changed the jquery selector to look for input#ID, and forgot. So I set that back and now it is generating the select box - but it is giving me those 2 Yes & No options. Not quite sure why it is doing that. It's not returning the values in from my url attribute.

Edit 3

@harish-shetty's suggestion seems to be working. But now, after it has successfully found the records via autocomplete and using the select2 menu, it is bypassing the setter method I have on my search.rb model.

Basically, what I want to happen is, once the user has finished filling out the form - and I have all the IDs/names for the neighborhoods they want, I want to create a new record in search_neighborhoods for those IDs.

So these are the methods I have:

Search.rb

  def neighborhood_names
    neighborhoods.map(&:name).join(',')
  end

  # we need to put [0] because it returns an array with a single element containing
  # the string of comma separated neighborhoods
  def neighborhood_names=(names)
    names[0].split(',').each do |name|
      next if name.blank?
      if neighborhood = Neighborhood.find_by_name(name)
        search_neighborhoods.build neighborhood_id: neighborhood.id
      end
    end
  end

My SearchController.rb

  def autocomplete_neighborhood_name
    @neighborhood = Neighborhood.select("id, name").where("name LIKE ?", "#{params[:name]}%").order(:name).limit(10)

    respond_to do |format|
      format.json { render json: @neighborhood , :only => [:id, :name] }
    end    
  end

This is what a request looks like right now - which shows that no search_neighborhood records are being created:

Started POST "/searches" for 127.0.0.1 at 2013-03-06 04:09:55 -0500
Processing by SearchesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"7SeA=", "search"=>{"boro_id"=>"", "neighborhood_names"=>"1416,1394", "property_type_id"=>"", "min_price"=>"", "max_price"=>"", "num_bedrooms"=>"", "num_bathrooms"=>""}}
  Neighborhood Load (0.5ms)  SELECT "neighborhoods".* FROM "neighborhoods" WHERE "neighborhoods"."name" = '1' LIMIT 1
   (0.3ms)  BEGIN
  SQL (0.8ms)  INSERT INTO "searches" ("amenity_id", "boro_id", "created_at", "keywords", "listing_type_id", "max_price", "min_price", "neighborhood_id", "num_bathrooms", "num_bedrooms", "property_type_id", "square_footage", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING "id"  [["amenity_id", nil], ["boro_id", nil], ["created_at", Wed, 06 Mar 2013 09:09:55 UTC +00:00], ["keywords", nil], ["listing_type_id", nil], ["max_price", nil], ["min_price", nil], ["neighborhood_id", nil], ["num_bathrooms", nil], ["num_bedrooms", nil], ["property_type_id", nil], ["square_footage", nil], ["updated_at", Wed, 06 Mar 2013 09:09:55 UTC +00:00]]
   (32.2ms)  COMMIT
Redirected to http://localhost:3000/searches/29
like image 446
marcamillion Avatar asked Feb 28 '13 21:02

marcamillion


People also ask

How do I initiate Select2?

Select2 will register itself as a jQuery function if you use any of the distribution builds, so you can call . select2() on any jQuery selector where you would like to initialize Select2. // In your Javascript (external . js resource or <script> tag) $(document).

What does Select2 () do?

Select2 gives you a customizable select box with support for searching, tagging, remote data sets, infinite scrolling, and many other highly used options.

What is Select2 plugin?

Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.

What Select2 dropdown?

By default, Select2 will attach the dropdown to the end of the body and will absolutely position it to appear above or below the selection container. Select2 will display the dropdown above the container if there is not enough space below the container, but there is enough space above it.


2 Answers

The select2 plugin supports auto-completion. You can use the native auto-completion as follows:

<%= f.input_field :ac_neighborhood_ids, 
      data: { 
        placeholder: "Where do you want to live?",
        saved: @search.neighborhoods.to_json,
        url: autocomplete_neighborhood_name_searches_path
      }, 
      input_html:  { class: "span8 ac-select2" }
%>

Javscript

$(document).ready(function() {  
  $('.ac-select2').each(function() {
    var url = $(this).data('url'); 
    var placeholder = $(this).data('placeholder'); 
    var saved = jQuery.parseJSON($(this).data('saved'));
    $(this).select2({
      minimumInputLength: 2,
      multiple: true,
      placeholder : placeholder,
      allowClear: true,
      ajax: {
        url: url,
        dataType: 'json',
        quietMillis: 500,
        data: function (term) {
          return {
            name: term
          };
        },
        results: function (data) {
          return {results: data};
        }
      },

      formatResult: function (item, page) {
        return item.name; 
      },

      formatSelection: function (item, page) {
        return item.name; 
      },

      initSelection : function (element, callback) {
        if (saved) {
          callback(saved);
        }
      }

    });
  });
});

Make sure the action at autocomplete_neighborhood_name_searches_path returns a json array of hashes. Each hash should contain id and name fields. The term for auto-completion is passed via the query parameter name.

  def autocomplete_neighborhood_name
    @neighborhood = Neighborhood.select("id, name").where("name LIKE ?", "#{params[:name]}%").order(:name).limit(10)

    respond_to do |format|
      format.json { render json: @neighborhood , :only => [:id, :name] }
    end    
  end

Your search model:

class Search

  attr_accessor :ac_neighborhood_ids

  has_many :search_neighborhoods
  has_many :neighborhoods, through: :search_neighborhoods

  def ac_neighborhood_ids
    neighborhood_ids.join(",")
  end

  def ac_neighborhoods
    neighborhoods.map{|n| {:id => n.id, :name => n.name}}
  end

  def ac_neighborhood_ids=(ids)
    search_neighborhoods.clear # remove the old values
    ids.split(',').select(&:present?).map do |neighborhood_id|
      search_neighborhoods.build neighborhood_id: neighborhood_id
    end
  end

end    
like image 54
Harish Shetty Avatar answered Oct 19 '22 14:10

Harish Shetty


I believe you need to attach select either to select tag (then it reads the data from it) or to input hidden tag, then you need to provide 'query' function. In your case it is attached to an input tag, and thus looks for a query function. Try setting as: :select on your f.input_field call.

like image 24
moonfly Avatar answered Oct 19 '22 16:10

moonfly