Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select2: Preselected item and correct rendering through templateSelection

When using Select2 v4, the suggested (actually the right) way to set a selected value programmatically, is to manipulate the underlying select element, add the desired <option> elements you want, set the value with $selectElement.val(<value>) and trigger a .trigger('change') event so that select2 plugin will update itself from the underlying select element. You can see this here.

The problem with this is when you have defined a templateSelection, that returns not just text for the selected value, but a whole HTML DOM (for instance, you may apply styling, add images, icons etc etc and return that as the rendered selection).

templateSelection accepts input as it comes from either an array datasource, or an ajax datasource etc. Each item represents one option but it may have more than just and id and a text. templateSelection may take into account many of the item's properties to produce the rendered output.

You can only define value and text in an <option> element. You cannot define the actual object (item) you want to set as selected, so that the templateSelection may produce the right output.

Is there a way to achieve that using only select2's API?

If not, is there any other workaround to have the value selected from code rendered correctly through templateSelection?

like image 906
Thanasis Ioannidis Avatar asked Jul 13 '17 12:07

Thanasis Ioannidis


People also ask

How do I programmatically select an option/item for a Select2 control?

The fourth parameter sets the options actual selected state - if set to true, the new option will be selected by default. You can use .find to select the option if it already exists, and create it otherwise: To programmatically select an option/item for a Select2 control, use the jQuery .val () method:

Are placeholders and pre-existing selections templated?

Anything rendered as a selection is templated. This includes placeholders and pre-existing selections that are displayed, so you must ensure that your templating functions can support them. Select2 multi-value select boxes can set restrictions regarding the maximum number of options that can be selected.

How to render HTML with jQuery selection template?

If you need to render HTML with your selection template, you must wrap your rendered selection in a jQuery object. In this case, the selection will be passed directly to jQuery.fn.append and will be handled directly by jQuery. Any markup, such as HTML, will not be escaped and it is up to you to escape any malicious input provided by users.

How does Select2 display the selected value in the container box?

When an option is selected from the dropdown menu, Select2 will display the selected value in the container box. By default, it will display the text property of Select2's internal representation of the selected option.


1 Answers

Just in case someone like me comes across this, the Select2 v4 manual provides an answer for this: https://select2.org/programmatic-control/add-select-clear-items#preselecting-options-in-an-remotely-sourced-ajax-select2

The following snippet is from the documentation. Essentially, you get the initial value via an ajax call, and set the initial value programmatically via the select2:select event.

// Set up the Select2 control
$('#mySelect2').select2({
    ajax: {
        url: '/api/students'
    }
});

// Fetch the preselected item, and add to the control
var studentSelect = $('#mySelect2');
$.ajax({
    type: 'GET',
    url: '/api/students/s/' + studentId
}).then(function (data) {
    // create the option and append to Select2
    var option = new Option(data.full_name, data.id, true, true);
    studentSelect.append(option).trigger('change');

    // manually trigger the `select2:select` event
    studentSelect.trigger({
        type: 'select2:select',
        params: {
            data: data
        }
    });
});

However, if you're using the templateSelection option, and are returning a jQuery object to provide a fancy one line formatted selection result, this solution will not work. In fact, triggering select2:select appears to do nothing.

Using jQuery, I found I could attach the data to the option, and from the templateSelection function, use this data as a fall back.

// create the option and append to Select2
var option = new Option(data.full_name, data.id, true, true);
$(option).data('raw', data);
studentSelect.append(option).trigger('change')

And in the templateSelection function:

templateSelection: function (result) {
    if (!result.id || result.loading) {
        return result.text
    }
    var $container = $(
        '<div class="clearfix">' +
            '<div class="pull-left select2-result__name"></div>' +
            '<div class="pull-right select2-result__finding_name"></div>' +
        '</div>'
    );

    var raw = $(result.element).data('raw')
    $container.find('.select2-result__name').text(result.name || raw.name || result.text)
    $container.find('.select2-result__finding_name').text(result.finding_name_1 || raw.finding_name_1)

    return $container
}

This example uses multiple fallbacks. We always try using what came in the results, as is provided in the normal ajax calls, but we fall back to the raw data from the initial option, and if that is lacking, fall back to the text field.

like image 195
Reuben Avatar answered Sep 28 '22 22:09

Reuben