Is it possible to paste a list to a select2 field and match each item in the list?
Asked Answered
T

2

16

I am using Select2 to manage large lists of data. Users have expressed a desire to be able to paste a list to the Select2 field in order to select various items at once instead of manually entering and matching each item in the list.

I have attempted to use tokenSeparators to separate the items in the list. This and the demo on tokens in the documentation lead me to believe that what I am hoping to do is possible, but so far I have had no joy.

The code I use to instantiate Select2 is:

$('input').select2({
    width: 'element',
    matcher: function (term, text) {
        return text.toUpperCase().indexOf(term.toUpperCase()) === 0;
    },
    minimumInputLength: 3,
    multiple: true,
    data: tagList, // tagList is an array of objects with id & text parameters
    placeholder: 'Manage List',
    initSelection: function (element, callback) {
        var data = [];
        $.each(function () {
            data.push({id: this, text: this});
        });
        callback(data);
    },
    tokenSeparators: [',', ', ', ' ']
});

Just to clarify, in all other respects the select2 field works. It's just that nothing is matched when a list is pasted into the field. I would like to test all the items in the pasted list. Is this possible and, if so, how?

Edit: I have tried the following code but it does not seem to work:

$('body').on('paste', '#s2id_list-unitids .select2-input', function () {
    var that = this;
    setTimeout(function () {
        var tokens = that.value.split(/[\,\s]+/);
        $('#list-unitids').val(tokens, true);console.log($('#list-unitids').select2('val'));
    }, 1);
});

And here is a fiddle I've created: http://jsfiddle.net/KCZDu/.

Tress answered 19/6, 2013 at 17:6 Comment(0)
M
20

select2 provides a tokenizer option that lets you pre-process the input. here is a possible implementation for your particular usecase:

tokenizer: function(input, selection, callback) {

        // no comma no need to tokenize
        if (input.indexOf(',')<0) return;

        var parts=input.split(",");
        for (var i=0;i<parts.length;i++) {
            var part=parts[i];
            part=part.trim();
            // todo: check for dupes (if part is already in [selection])

            // check if the part is valid
            // todo: you will need a better way of doing this
            var valid=false;
            for (var j=0;j<unitIds.length;j++) {
                if (part===unitIds[j]) { valid=true; break; }
            }

            if (valid) callback({id:part,text:part});
        }
    }

here is a working fiddle: http://jsfiddle.net/XcCqg/38/

also note your original fiddle uses select2 3.2 which is very outdated and may not support the tokenizer.

Mccarley answered 21/6, 2013 at 15:12 Comment(2)
Thank you! I can now relax this weekend! :)Tress
Don't know if it is because of a setting but I got error "TypeError: input.indexOf is not a function" when focus into the input. Also it doesn't prevent duplicatesParamount
B
2

Basically it overrides the default paste function to handle the new input text, this code will break the input based on the separators specified in the option 'tokenSeparators', then adds them all to the list separated, you only need to run this code at the end of your page:

$(document).on('paste', 'span.select2', function (e) {
        e.preventDefault();
        var select = $(e.target).closest('.select2').prev();
        var clipboard = (e.originalEvent || e).clipboardData.getData('text/plain');
        var createOption = function (value, selected) {
            selected = typeof selected !== 'undefined' ? selected : true;
            return $("<option></option>")
                .attr("value", value)
                .attr("selected", selected)
                .text(value)[0]
        };
        $.each(
            clipboard.split(new RegExp(select.data('select2').options.options.tokenSeparators.map(function (a) {
                return (a).replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
            }).join('|'))),
            function (key, value) {
                if (value && (!select.val() || (select.val() && select.val().indexOf('' + value) == -1))) {
                    select.append(createOption(value));
                }
            });
        select.trigger('change');
    });
Barros answered 3/5, 2016 at 14:26 Comment(2)
Can you please add a note explaining what it does?Ursas
@Ursas basically it overrides the default paste function for select2 fields to handle the new input text, this code will break the input based on the separators specified in option 'tokenSeparators', then adds all of them to the list of options separated. hope you understand my bad english :)Barros

© 2022 - 2024 — McMap. All rights reserved.