Search doesn't work with dependent dropdown + template


#1

I have 2 lists. When I select a value in the first one, it updates the options in the second list. Only the second list is a Select2.

I made it work but the search functionality of Select2 doesn’t work.

If I check the DOM, I notice that the options generated by Select2 don’t have a text. Is it because of it that the search doesn’t work ?

<select class="form-control measure select2-hidden-accessible" name="measures[]" data-select2-id="4" tabindex="-1" aria-hidden="true">
	<option value="" data-select2-id="6">- Select a measure -</option>
	<option value="Std_Biceps" data-select2-id="818"></option>
	<option value="Std_EB_DW_5" data-select2-id="819"></option>
	<option value="Std_EB_DW_8" data-select2-id="820"></option>
	<option value="Std_Forearm_C" data-select2-id="821"></option>
</select>

Here is my JS code :

$('.category').change(function(event) {
    var measure = $(this).parents('.row').find('.measure');

    // Modify placeholder when searching
    measure.prop('disabled', true).select2({placeholder: "Searching..."});

    // Remove existing options of the list (of a previous usage)
    measure.children('option').each(function(index, el) {
        if ($(el).val().length > 0)
            $(el).remove();
    });

    var DATA = 'tagcat=' + $(this).val();

    $.ajax({
        type    : "GET",
        url     : $('.custom-table-container').data('search-js'),
        data    : DATA,
        cache   : false,
        success : function(response) {
            var data = JSON.parse(response);

            // Update the measures list    
            measure.select2({
                allowClear       : true,
                data             : data.items,
                escapeMarkup     : function (markup) { return markup; },
                templateResult   : formatTag,
                templateSelection: formatTagSelect
            }).prop('disabled', false);
        }
    });
});

I was able to make the search work in adding manually the HTML options in the list but I loose the results template… I have just simple results with only the dispay of the name (no picture, no id code).

<select class="form-control measure select2-hidden-accessible" name="measures[]" data-select2-id="4" tabindex="-1" aria-hidden="true">
	<option value="" data-select2-id="6">- Select a measure -</option>
	<option value="Std_Biceps" data-select2-id="18">Arm circumference</option>
	<option value="Std_EB_DW_5" data-select2-id="19">Circumference 5cm under the elbow</option>
	<option value="Std_EB_DW_8" data-select2-id="20">Circumference 8cm under the elbow</option>
	<option value="Std_Forearm_C" data-select2-id="21">Elbow circumference</option>
</select>

Code :

$.ajax({
    // ...
    success : function(response) {
        var data = JSON.parse(response);

        data.items.forEach(function(tag) {
            // create the option and append to Select2
            var option = new Option(tag.name, tag.id, false, false);
            measure.append(option);
        });

        measure.select2({
            allowClear          : true,
            data                : data.items,
            escapeMarkup        : function (markup) { return markup; },
           templateResult       : formatTag,
           templateSelection    : formatTagSelect
        }).prop('disabled', false);
    }
});

How am I suppose to code this to have both templating and search ?
Thanks for your help. :slight_smile:


#2

When you use Select2’s AJAX feature to retrieve data, it expects any results matching/filtering to be done on the server side. In other words, the URL that receives your AJAX request is expected to handle some URL query parameters that (among other things) include the user’s current search term, and to return only the data that matches that term. One consequence of this is that Select2’s “built-in” search capability does not work. (See the “info” box at the end of this section of the Select2 documentation.)

Also, when using the AJAX feature, Select2 does not actually create an HTML <option> element until the user selects an item from the Select2 results list.

Templating should work with an AJAX data source, but if you’re going to use the built-in AJAX feature, you’ll need to arrange to do your filtering on the server side, based on the search term that is passed to your AJAX endpoint URL. If you can’t make that happen then I recommend you retrieve the data (presumably the full data set) outside of the Select2 (e.g., using native Javascript XHR or fetch() methods, or jQuery’s AJAX feature), and then initialize the Select2 with that data (make sure you return it in the expected format). Then, since the data is “local” to the Select2, you can use Select2’s built-in search feature.

If you want to use Select2’s built-in AJAX capability, I recommend you carefully read the Ajax (remote data) documentation, which explains what I wrote above in more detail and provides sample code.


#3

First of all, thank you for your reply.

I don’t really need the built-in AJAX feature of Select2 because I already filter my results with the first list (by choosing a category). I just need the search to “go to” a specific option (just like in my second example). I don’t know if I am clear enough…

The following picture shows the results of my second code example (without templating). The search is working well. No request is done in AJAX here. The “search” displays only options that have the keyword in their text. I need the same but with my template. I don’t know why my template doesn’t work.

2019-05-20%2009_25_50-Add%20size%20table%20%C2%B7%20Thuasne%20Product%20Manager

I recommend you retrieve the data (presumably the full data set) outside of the Select2 (e.g., using native Javascript XHR or fetch() methods, or jQuery’s AJAX feature), and then initialize the Select2 with that data

I’ll try that. I think if I init the Select2 only after choosing a category (and not at the display of the page), maybe it should work…


#4

Sorry, I just found where I was wrong : I didn’t show the right data inside my template result function.
So, in a case it worked because a specific data didn’t exist and, in the other case, that data existed and it replaced a specific template I did… It’s not very effective to work on it a friday afternoon. :smile:

So the right way to do this is to add manually the options of the select in the DOM and init the Select2 after.

 $.ajax({
    // ...
    success : function(response) {
        var data = JSON.parse(response);

        // create options in the DOM
        data.items.forEach(function(tag) {
            // create the option and append to Select2
            var option = new Option(tag.name, tag.id, false, false);
            measure.append(option);
        });

        // init Select2 with data
        measure.select2({
            theme		        : "bootstrap4",
            placeholder	        : "- Select a measure -",
            allowClear          : true,
            data                : data.items,
            escapeMarkup        : function (markup) { return markup; },
           templateResult       : formatTag,
           templateSelection    : formatTagSelect
        });
    }
});

#5

Yes, you will need to reinitialize the Select2 every time you load new data into it.

Let me know how you get on, and if you have any other problems I’ll try to help you resolve them.