
I think many are familiar with
Select2 . Everything in it is wonderful: both the elements are beautiful, and the customization of the car, and c ajax works and can do much more useful things. Only problem is one: initialization is rather cumbersome (js should be written, actions should be for
ajax loading results, and so on). It was not very convenient and we decided to make our
add2 for
Select2 , in which we don’t need to write js either, and we almost don’t have to go outside the view. About how we did it and what happened read under the cut.
What were you aiming for?
Everyone knows the behavior of helpers from
ActionView :: Helpers :: FormTagHelper . For example
select_tag :
select_tag "people", options_from_collection_for_select(@people, "id", "name")
I want to work with
Select2 as well. And with any variation of
Select2 : whether it is a static replacement for the usual
select ,
ajax option or multi
select .
What happened? It turned out about the following:
= select2_ajax_tag :my_select2_name, {class_name: :my_model_name, text_column: :name, id_column: :id}, my_init_value_id, placeholder: 'Fill me now!'
This is the easiest helper call. No need for additional gestures. As a result, we get a select with dynamic loading of variants from the
MyModelName model.
')
Of course, this is the easiest way to use. If there is a desire to make complex selections, to produce different results depending on other parameters on the page, to customize the display of options in the selection, etc., it does not matter, all this can be done, but you will have to add a little
Ruby .
Examples in the studio!
For those who already want to touch with their hands, as well as those who perceive the source code better than a leisurely verbal description, I give a
link to the RoR project with an example of use.
Alternatives
At one time, we did not find them, so the slow invention of this heme happened. However, given the specificity of the resource and the power of comments, I am sure that someone will prompt an analog which we did not notice. So I will be glad if you point out an alternative.
What is it all about?
These are the two heme
AutoSelect2 and
AutoSelect2Tag idea which proposed
Tab10id . Both
gems are based on
select2-rails and allow you to create Select2 elements without heavy thoughts about js initialization and other overhead.
How to use it?
Detailed
readme has each of the gems, but they, as usual, in English. Therefore, I will tell you in Russian about how to put the gems correctly, what they require for work and how to use their functionality as a result.
Installation
First of all, it’s necessary to say that if you have the asset pipeline shut down, the installation becomes rather nontrivial and is beyond the scope of this article, so we’ll assume that everything’s fine with the pipeline.
Now the points:
- you need to install select2-rails , set its scripts in application.js and styles in application.css (or what do you have instead of them?)
- install AutoSelect2 and set its scripts in application.js (or add helpers to the necessary partials)
- check that there is no controller in the project named Select2AutocompletesController and similar routes
get 'select2_autocompletes/:class_name'
- prepare an 'app / select2_search_adapter' folder for your SearchAdapter
- install gem autoselect2tag
Use static select2
After these actions, you can use a helper for a static select:
= select2_tag :select2_name, my_options_for_select2(my_init_value), placeholder: 'Fill me!', include_blank: true, select2_options: {width: 'auto'}
In essence, the method is a wrapper for the usual
select_tag . It adds the necessary classes to initialize
Select2 and forward
the constructor parameters .
Using ajax Select2
The simplest helper call is available straight out of the box:
= select2_ajax_tag :my_select2_name, {class_name: :my_model_name, text_column: :name, id_column: :id}, my_init_value_id, placeholder: 'Fill me now!'
Here the second parameter of the helper should speak for itself.
If you want more complex constructions in the select, you will have to write your
SearchAdapter . What it is? This is the class that gives page by page hashes with options for the select and is responsible for the initialization value, if present. This class is used in the
Select2AutocompletesController controller, and its name is indicated in the second parameter
select2_ajax_tag (see the example below). Here is a set of requirements for
SearchAdapter :
- files with classes should be located in 'app / select2_search_adapter' (by analogy with inputs from formtastic ); it is fair to say that they can be located in any other autoload directory, but the method described above seems to be the most optimal
- class names must end with SearchAdapter
- SearchAdapter should inherit from AutoSelect2 :: Select2SearchAdapter :: Base
- the class must implement the search_default method (see below for details)
In order not to describe the requirements for
search_default for a
long time, I
’ll give an example of a minimalist
SearchAdapter :
class SystemRoleSearchAdapter < AutoSelect2::Select2SearchAdapter::Base class << self def search_default(term, page, options) if options[:init].nil? roles = default_finder(SystemRole, term, page: page) count = default_count(SystemRole, term) { items: roles.map do |role| { text: role.name, id: role.id.to_s }
As can be seen from the example, if the
options : key is missing: init, then
search_default should return a hash of the form:
{ items: [ { text: 'first element', id: 'first_id' }, { text: 'second element', id: 'second_id' } ], total: count }
If: init is present, the function should return:
{text: 'displayed text', id: 'id_of_initial_element'}
After defining such a class, you can use ajax select2 as follows:
= select2_ajax_tag :my_select2_name, :system_role, init_value, additional_options
And that's all. The syntax is as close as possible to
select_tag and can be used anywhere in the application.
Using multi ajax Select2
Here, everything is similar to the previous item with
ajax select2 with the only difference that you need to include the
multi_ajax_select2_value_parser.js script and add to the
select2_options hash
: {multiple: true} :
= select2_ajax_tag :multi_countries_select2, :country, '', class: 'is-multiple', select2_options: {multiple: true}
Somewhere here, developers familiar with
Select2 should have a question: why the script? I answer: the script implements the serialization of select options as an array, and not as a string with options separated by commas. Author
Select2 promised to do the same in the next major version, but I don’t want to wait.
Additional features
Most of them are described in the
example . For those who are too lazy to launch the project, and just to complete the picture, I will make a brief overview.
Search_default extension
Suppose you created your
SearchAdapter and implemented
search_default in it. Let this adapter be for the User model. Everything is good, but once it was necessary to create a similar select, but in the variants there were only active users. In order not to create a new class for the same entity, you can add the
search_active method to the previously created
UserSearchAdapter and specify this method when initializing
Select2 :
= select2_ajax_tag :active_user, :user, '', search_method: :active
Dependent samples
Another case: implement 2 (or more) selects, the options in which depend on each other. For example, a cascade selection of a country and a city (an example from
auto_select2_tag_example ). If you choose a country, then you can choose a city only within this country and vice versa. As it is inconveniently done with static and so it is clear. And this is how it is done with
select2_ajax_tag : first, you need to assign a class to all dependent elements, for example
dependent-input ; secondly, specify this class in
additional_ajax_data :
= select2_ajax_tag :country_id, :country, '', placeholder: 'Select country', class: 'dependent-input', select2_options: {additional_ajax_data: {selector: '.dependent-input'}} = select2_ajax_tag :city_id, :city, '', placeholder: 'Select city', class: 'dependent-input', select2_options: {additional_ajax_data: {selector: '.dependent-input'}}
After that, when sending an ajax request for receiving options, the select will search for all elements with the
dependent-input class, exclude itself from them, convert the remaining ones to json, where the key is the element's name-attribute and value is the value-attribute, and send the received json along with the request. The controller, on the
other hand, forwards all these parameters in
SearchAdapter and in the
search_default method (or any other
search_ ) in the
options parameter there will be values from the form. Then they can be used in any convenient way and give only those options that meet the requirements.
Method to_select2
You can
omit the text_column and
id_column options if the model has a
to_select2 method. In this case, it will be automatically called to get options when generating
json . If you need to use a method other than
to_select2 , then you can pass the
hash_method parameter:
= select2_ajax_tag :default_country_id, {class_name: :country, hash_method: :to_select2_alternate}, Country.first.id
The benefit is obvious. Without creating a
SearchAdapter, you can transfer more complex options to a select.
A few words about initialization
Elements are automatically initialized after the page is loaded (that is, in
$ (document). Ready () ), after
ajax requests (at the ajaxSuccess
event ) and after the
cocoon: after-insert event from
cocoon . There is no need to worry about re-initialization, nothing is caused twice and there are no problems. If for some reason, manual initialization is still required, then
initAutoAjaxSelect2 () and / or
initAutoStaticSelect2 () should be called.
Future plans
Since gems are grown from the
Redmine project, I want to do
pluging for it. Of course, here immediately raises the question of the pipeline, which in
Redmine does not work in principle and for the launch of which you need to thoroughly
try . Next, I want to make friends with
formtastic .
Behind this all
Thank you for reading to the end. Write about typos and inaccuracies in HP, I will be glad to fix it. Other questions / comments / suggestions / indignations write in the comments, it will be interesting.