MikeOShay MikeOShay - 5 months ago 47
JSON Question

Select2 4.0.0 can't select results

I'm trying to use the newest version of Select2 to query my site's API and return a multiple-select. It's fetching the right data and it's even formatting the dropdown properly, combining two keys in the returned objects as "(A-123) John Johnson", but the dropdown's not responding to mouseover or clicks.

I'm using the select2.full.min.js and select2.min.css files. For the purposes of the project, I'm including them in the directory and accessing them through Bundles in cshtml, instead of accessing them via a CDN.

HTML:

<div>
<select class="user-list" multiple="multiple" style="width: 100%">
</select>
</div>


At the moment, it's looking like this, which is how I want it:
properly-formatted dropdown

Not sure if this is relevant, but when I browse the generated source code while searching, the input looks fine, but the dropdown's code is greyed out as though it were hidden.

solid/opaque input code

greyed out dropdown code

Per other suggestions I've found on here and elsewhere, I've tried a few different solutions. I eventually found out how templateResult and templateSelection are supposed to work (not particularly thanks to the documentation), and tried returning the ID as well, but I still can't seem to actually select anything, or even get a response when I hover over the options.

Here's what I wound up with, including some debugging to make sure the returned object is valid.

JS:

// Setup autocomplete/select for User filter
$(".user-list").select2({
ajax: {
url: "[api url]",
type: "GET",
dataType: "json",
data: function (params) {
return {
search: params.term, // search term
page: params.page
};
},
processResults: function (data) {
console.log(JSON.stringify(data));
return {
results: data
};
},
},
escapeMarkup: function (markup) { return markup; },
id: function (data) { return data.Id.toString(); },
minimumInputLength: 1,
templateResult: function (data, page) {
return "(" + data.User + ") " + data.Name;
},
templateSelection: function (data, page) {
return "(" + data.User + ") " + data.Name;
}
})


The ID is a GUID, and there are two other fields, which I'll call Name and User.

Data Sample:

[
{
"Id":"a1a1a1a1-a1a1-a1a1-a1a1-a1a1a1a1a1a1",
"Name":"John Johnson",
"User":"A-123"
},
{
"Id":"b2b2b2b2-b2b2-b2b2-b2b2-b2b2b2b2b2b2",
"Name":"Tom Thompson",
"User":"B-456"
}
]


I hate to add to the pile of questions that seem to be about this, but most results I've found have been for the older version with significantly different options, and they just haven't worked for me yet.

Answer

The way select2 operates is that it uses the "id" values of each data object and puts those into the original Select element as the selected option(s). This is case-sensitive.

By default, it displays the dropdown options and the selected element by whatever the "text" value is of the data object. This does not allow for custom formatting.

If (like me) you want to return different data options, you still need to return a field as "id", or re-map a field to "id" in an object returned in the processResults option under ajax. Then use the templateResult and templateSelection settings with your other returned data to display what you want.

If you return and parse everything correctly except for the id, you may wind up with an otherwise functional list, but be unable to select any options.

The requirements for the dropdown changed a bit with my project, but here's where I wound up. It works fine the multiple="multiple" attribute added to to make it a multi-select, too.

<select class="select2" style="width:100%; height: 100%;">
    <option></option>
</select>

$(".select2").select2({
    ajax: {
        url: "[api url]",
        method: "get",
        data: function (params) {
            return {
                search: params.term
            };
        },
        processResults: function (data) {
            return {
                results: data
            };
        },
        cache: true
    },
    placeholder: "Enter a User ID or Name",
    templateResult: function(data) {
            return "(" + data.user + ") " + data.name;
    },
    templateSelection: function(data) {
        return "(" + data.user + ") " + data.name;
    }
}).ready(function () {
    $(".select2-selection__placeholder").text("Enter a User ID or Name")
})

It's possible part of my initial issue was all the attempts at implementing fixes for older versions of Select2, which had a completely different set of options/settings available.

Additionally, a bit of a side-note, the "placeholder" attribute doesn't currently work with custom templating. It tries to force the placeholder text into the Result format, which shows "(undefined) undefined" with this code. To fix it requires an empty option and to replace the text on select2.ready.