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.coffee
file:
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
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).
Select2 gives you a customizable select box with support for searching, tagging, remote data sets, infinite scrolling, and many other highly used options.
Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With