Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Changed query to select only the used columns, added an :extra_data o…

…ption to retrieve extra columns and return them in the JSON response, added :update_elements option to the form_helpers to be able to update any HTML element with any of the extra column data returned, fixed form_helpers to maintain the original functionality of text_field and text_field_tag
  • Loading branch information...
commit 1067e4b3dc40952fbb46b70ec0497e5b55b3ce90 1 parent b3c18ac
@jakemack jakemack authored
30 README.markdown
@@ -42,7 +42,7 @@ Install it
Run the generator
rails generate autocomplete
-
+
And include autocomplete-rails.js on your layouts
javascript_include_tag "autocomplete-rails.js"
@@ -105,6 +105,16 @@ Only the following terms mould match the query 'un':
* Unacceptable
+#### :extra_data
+
+By default, your search will only return the required columns from the database needed to populate your form, namely id and the column you are searching (name, in the above example).
+
+Passing an array of attributes/column names to this option will fetch and return the specified data.
+
+ class ProductsController < Admin::BaseController
+ autocomplete :brand, :name, :extra_data => [:slogan]
+ end
+
#### :display_value
If you want to display a different version of what you're looking for, you can use the :display_value option.
@@ -126,6 +136,8 @@ In the example above, you will search by _name_, but the autocomplete list will
This wouldn't really make much sense unless you use it with the :id_element HTML tag. (See below)
+Only the object's id and the column you are searching on will be returned in JSON, so if your display_value method requires another parameter, make sure to fetch it with the :extra_data option
+
### View
On your view, all you have to do is include the attribute autocomplete on the text field
@@ -156,6 +168,20 @@ If you need to use the id of the selected object, you can use the *:id_element*
This will update the field with id *#some_element with the id of the selected object. The value for this option can be any jQuery selector.
+### Getting extra object data
+
+If you need to extra data about the selected object, you can use the *:update_elements* HTML attribute.
+
+The :update_elements attribute accepts a hash where the keys represent the object attribute/column data to use to update and the values are jQuery selectors to retrieve the HTML element to update:
+
+ f.autocomplete_field :brand_name, autocomplete_brand_name_products_path, :update_elements => {:id => '#id_element', :slogan => '#some_other_element'}
+
+ class ProductsController < Admin::BaseController
+ autocomplete :brand, :name, :extra_data => [:slogan]
+ end
+
+The previous example would fetch the extra attribute slogan and update jQuery('#some_other_element') with the slogan value.
+
## Formtastic
If you are using [Formtastic](http://github.com/justinfrench/formtastic), you automatically get the *autocompleted_input* helper on *semantic_form_for*:
@@ -232,6 +258,6 @@ integration folder:
# About the Author
-[Crowd Interactive](http://www.crowdint.com) is an American web design and development company that happens to work in Colima, Mexico.
+[Crowd Interactive](http://www.crowdint.com) is an American web design and development company that happens to work in Colima, Mexico.
We specialize in building and growing online retail stores. We don’t work with everyone – just companies we believe in. Call us today to see if there’s a fit.
Find more info [here](http://www.crowdint.com)!
View
30 lib/generators/templates/autocomplete-rails.js
@@ -6,7 +6,7 @@
*
* Example:
* <input type="text" data-autocomplete="/url/to/autocomplete">
-*
+*
* Optionally, you can use a jQuery selector to specify a field that can
* be updated with the element id whenever you find a matching value
*
@@ -28,16 +28,16 @@ $(document).ready(function(){
}
});
};
-
+
jQuery.railsAutocomplete = function (e) {
_e = e;
this.init(_e);
};
-
+
jQuery.railsAutocomplete.fn = jQuery.railsAutocomplete.prototype = {
railsAutocomplete: '0.0.1'
};
-
+
jQuery.railsAutocomplete.fn.extend = jQuery.railsAutocomplete.extend = jQuery.extend;
jQuery.railsAutocomplete.fn.extend({
init: function(e) {
@@ -48,12 +48,19 @@ $(document).ready(function(){
function extractLast( term ) {
return split( term ).pop().replace(/^\s+/,"");
}
-
+
$(e).autocomplete({
source: function( request, response ) {
$.getJSON( $(e).attr('data-autocomplete'), {
term: extractLast( request.term )
- }, response );
+ }, function() {
+ $(arguments[0]).each(function(i, el) {
+ var obj = {};
+ obj[el.id] = el;
+ $(e).data(obj);
+ });
+ response.apply(null, arguments);
+ });
},
search: function() {
// custom minLength
@@ -81,8 +88,15 @@ $(document).ready(function(){
if ($(this).attr('id_element')) {
$($(this).attr('id_element')).val(ui.item.id);
}
- };
-
+ if ($(this).attr('data-update-elements')) {
+ var data = $(this).data(ui.item.id.toString());
+ var update_elements = $.parseJSON($(this).attr("data-update-elements"));
+ for (var key in update_elements) {
+ $(update_elements[key]).val(data[key]);
+ }
+ }
+ }
+
return false;
}
});
View
14 lib/rails3-jquery-autocomplete/autocomplete.rb
@@ -1,22 +1,22 @@
module Rails3JQueryAutocomplete
# Inspired on DHH's autocomplete plugin
- #
+ #
# Usage:
- #
+ #
# class ProductsController < Admin::BaseController
# autocomplete :brand, :name
# end
#
- # This will magically generate an action autocomplete_brand_name, so,
+ # This will magically generate an action autocomplete_brand_name, so,
# don't forget to add it on your routes file
- #
+ #
# resources :products do
# get :autocomplete_brand_name, :on => :collection
# end
#
# Now, on your view, all you have to do is have a text field like:
- #
+ #
# f.text_field :brand_name, :autocomplete => autocomplete_brand_name_products_path
#
#
@@ -31,12 +31,12 @@ def autocomplete(object, method, options = {})
#allow specifying fully qualified class name for model object
class_name = options[:class_name] || object
items = get_autocomplete_items(:model => get_object(class_name), \
- :options => options, :term => term, :method => method)
+ :options => options, :term => term, :method => method)
else
items = {}
end
- render :json => json_for_autocomplete(items, options[:display_value] ||= method)
+ render :json => json_for_autocomplete(items, options[:display_value] ||= method, options[:extra_data])
end
end
end
View
16 lib/rails3-jquery-autocomplete/form_helper.rb
@@ -3,7 +3,7 @@ module Helpers
module FormHelper
alias_method :original_text_field, :text_field
def text_field(object_name, method, options = {})
- original_text_field(object_name, method, rename_autocomplete_option(options))
+ original_text_field(object_name, method, options)
end
# Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) and
@@ -14,15 +14,15 @@ def text_field(object_name, method, options = {})
# # => <input type="text" id="post_title" name="post[title]" size="20" value="#{@post.title}" data-autocomplete="author/autocomplete"/>
#
def autocomplete_field(object_name, method, source, options ={})
- options[:autocomplete] = source
- text_field(object_name, method, options)
+ options["data-autocomplete"] = source
+ text_field(object_name, method, rename_autocomplete_option(options))
end
end
module FormTagHelper
alias_method :original_text_field_tag, :text_field_tag
def text_field_tag(name, value = nil, options = {})
- original_text_field_tag(name, value, rename_autocomplete_option(options))
+ original_text_field_tag(name, value, options)
end
# Creates a standard text field that can be populated with jQuery's autocomplete plugin
@@ -32,8 +32,8 @@ def text_field_tag(name, value = nil, options = {})
# # => <input id="address" name="address" size="75" type="text" value="" data-autocomplete="address/autocomplete"/>
#
def autocomplete_field_tag(name, value, source, options ={})
- options[:autocomplete] = source
- text_field_tag(name, value, options)
+ options["data-autocomplete"] = source
+ text_field_tag(name, value, rename_autocomplete_option(options))
end
end
@@ -42,8 +42,8 @@ def autocomplete_field_tag(name, value, source, options ={})
# data-autocomplete key
#
private
- def rename_autocomplete_option(options)
- options["data-autocomplete"] = options.delete(:autocomplete)
+ def rewrite_autocomplete_option(options)
+ options["data-update-elements"] = JSON.generate(options.delete :update_elements) if options[:update_elements]
options
end
end
View
28 lib/rails3-jquery-autocomplete/helpers.rb
@@ -4,11 +4,18 @@ module Rails3JQueryAutocomplete
module Helpers
#
- # Returns a three keys hash actually used by the Autocomplete jQuery-ui
+ # Returns a hash with three keys actually used by the Autocomplete jQuery-ui
# Can be overriden to show whatever you like
+ # Hash also includes a key/value pair for each method in extra_data
#
- def json_for_autocomplete(items, method)
- items.collect {|item| {"id" => item.id, "label" => item.send(method), "value" => item.send(method)}}
+ def json_for_autocomplete(items, method, extra_data)
+ items.collect do |item|
+ hash = {"id" => item.id, "label" => item.send(method), "value" => item.send(method)}
+ extra_data.each do |datum|
+ hash[datum] = item.send(datum)
+ end if extra_data
+ hash
+ end
end
# Returns parameter model_sym as a constant
@@ -22,7 +29,7 @@ def get_object(model_sym)
# Returns a symbol representing what implementation should be used to query
# the database and raises *NotImplementedError* if ORM implementor can not be found
- def get_implementation(object)
+ def get_implementation(object)
ancestors_ary = object.ancestors.collect(&:to_s)
if ancestors_ary.include?('ActiveRecord::Base')
:activerecord
@@ -45,7 +52,7 @@ def get_autocomplete_order(implementation, method, options)
case implementation
when :mongoid then
- if order
+ if order
order.split(',').collect do |fields|
sfields = fields.split
[sfields[0].downcase.to_sym, sfields[1].downcase.to_sym]
@@ -53,7 +60,7 @@ def get_autocomplete_order(implementation, method, options)
else
[[method.to_sym, :asc]]
end
- when :activerecord then
+ when :activerecord then
order || "#{method} ASC"
end
end
@@ -79,10 +86,10 @@ def get_items(parameters)
# Can be overriden to return or filter however you like
# the objects to be shown by autocomplete
#
- # items = get_autocomplete_items(:model => get_object(object), :options => options, :term => term, :method => method)
+ # items = get_autocomplete_items(:model => get_object(object), :options => options, :term => term, :method => method)
#
def get_autocomplete_items(parameters)
- model = parameters[:model]
+ model = relation = parameters[:model]
method = parameters[:method]
options = parameters[:options]
term = parameters[:term]
@@ -91,13 +98,14 @@ def get_autocomplete_items(parameters)
limit = get_autocomplete_limit(options)
implementation = get_implementation(model)
order = get_autocomplete_order(implementation, method, options)
+ relation = model.select([:id, method] + (options[:extra_data].blank? ? [] : options[:extra_data])) unless options[:full_model]
case implementation
when :mongoid
search = (is_full_search ? '.*' : '^') + term + '.*'
- items = model.where(method.to_sym => /#{search}/i).limit(limit).order_by(order)
+ items = relation.where(method.to_sym => /#{search}/i).limit(limit).order_by(order)
when :activerecord
- items = model.where(["LOWER(#{method}) LIKE ?", "#{(is_full_search ? '%' : '')}#{term.downcase}%"]) \
+ items = relation.where(["LOWER(#{method}) LIKE ?", "#{(is_full_search ? '%' : '')}#{term.downcase}%"]) \
.limit(limit).order(order)
end
end
View
4 test/form_helper_test.rb
@@ -6,12 +6,12 @@ class Post
class FormHelperTest < ActionView::TestCase
def test_text_field_tag
- assert_match(/data-autocomplete=\"some\/path\"/, text_field_tag('field_name', '', :autocomplete => 'some/path'))
+ assert_match(/autocomplete=\"some\/path\"/, text_field_tag('field_name', '', :autocomplete => 'some/path'))
end
def test_text_field
post = Post.new
- assert_match(/data-autocomplete=\"some\/path\"/, text_field(:post, :author, :autocomplete => 'some/path'))
+ assert_match(/autocomplete=\"some\/path\"/, text_field(:post, :author, :autocomplete => 'some/path'))
end
def test_autocomplete_field_tag
View
6 test/helpers.rb
@@ -11,7 +11,7 @@ class HelpersTest < ::Test::Unit::TestCase
end
items_exist_assert = lambda do |model|
- items = Helpers.get_items(:model => model), :term => 'A', :method => 'name')
+ items = Helpers.get_items(:model => model), :term => 'A', :method => 'name')
assert(items)
assert_equal(3, items.size)
end
@@ -30,7 +30,7 @@ class HelpersTest < ::Test::Unit::TestCase
response.each(&assert_structure)
end
end
-
+
context 'looking for items' do
include Rails3JQueryAutocomplete::Mongoid::Test
@@ -48,7 +48,7 @@ class HelpersTest < ::Test::Unit::TestCase
context 'passing an ActiveRecord query result' do
include Rails3JQueryAutocomplete::ActiveRecord::Test
-
+
should 'parse items to JSON' do
response = Helpers.json_for_autocomplete(Game.all, :name)
assert_not_nil(response)
Please sign in to comment.
Something went wrong with that request. Please try again.