📜 ⬆️ ⬇️

How we select2 in helper wrapped

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:
  1. 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?)
  2. install AutoSelect2 and set its scripts in application.js (or add helpers to the necessary partials)
  3. check that there is no controller in the project named Select2AutocompletesController and similar routes
     get 'select2_autocompletes/:class_name' 
  4. prepare an 'app / select2_search_adapter' folder for your SearchAdapter
  5. 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 :

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 } #     'class_name' end, total: count } else get_init_values(SystemRole, options[:item_ids]) end end end end 

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 #    search_    

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.

Source: https://habr.com/ru/post/244553/


All Articles