Select2 Event for creating a new tag
Asked Answered
I

4

23

I'm using the jQuery Select2 (v4) plugin for a tag selector.

I want to listen for when a new tag is created in the select element and fire an ajax request to store the new tag. I discovered there is the createTag event but this seems to fire every time a letter is entered into the select2 element. As shown in my fiddle: http://jsfiddle.net/3qkgagwk/1/

Is there a similar event that only fires when the new tag has finished being entered? I.e. it's enclosed by a grey box enclosing it.

Indite answered 22/2, 2015 at 10:50 Comment(4)
Can't you just use the :select event? So every time something is selected, you get it like this: $(selector).on("select2:select", function (e) { console.log(e.params.data); });. This indeed does not make a difference between existing vs. new objects, but its a start.Monnet
#23295668Dramatics
createTag isn't an event but a method that's overridden. It looks like the developer responded to your question on Gitlab about this the next day (github.com/select2/select2/issues/3063) - it would have been nice had you updated your question or provided an answer. For others, the develop suggested listening for the select2:selected event; I've found that a change event is fired also.Interplead
may the coding gods bless you @InterpleadFractocumulus
R
46

I can't find any native method unfortunately. But if you're interested in simple "workarounds", maybe this get you closer:

$('.select2').select2({
    tags: true,
    tokenSeparators: [",", " "],
    createTag: function (tag) {
        return {
            id: tag.term,
            text: tag.term,
            // add indicator:
            isNew : true
        };
    }
}).on("select2:select", function(e) {
    if(e.params.data.isNew){
        // append the new option element prenamently:
        $(this).find('[value="'+e.params.data.id+'"]').replaceWith('<option selected value="'+e.params.data.id+'">'+e.params.data.text+'</option>');
        // store the new tag:
        $.ajax({
            // ... 
        });
    }
});

DEMO


[EDIT]
(Small update: see @Alex comment below)

The above will work only if the tag is added with mouse. For tags added by hitting space or comma, use change event.

Then you can filter option with data-select2-tag="true" attribute (new added tag):

$('.select2').select2({
    tags: true,
    tokenSeparators: [",", " "]
}).on("change", function(e) {
    var isNew = $(this).find('[data-select2-tag="true"]');
    if(isNew.length && $.inArray(isNew.val(), $(this).val()) !== -1){
        isNew.replaceWith('<option selected value="'+isNew.val()+'">'+isNew.val()+'</option>');
        $.ajax({
            // ... store tag ...
        });
    }
});

DEMO 2

Regardless answered 22/2, 2015 at 12:18 Comment(12)
How do i detect if the tag was removed ?Stroll
I want only when the new tag is removed eventStroll
Then you could add an indicator (like class) when new tag is created and simply check that indicator in :unselect event handler. DemoRegardless
@did you test your code ? Please try to remove the newly created tag using the bakcspace key! the tag is doubled or something :(Stroll
? any thoughts about this issueStroll
Though I haven't tested it much as it was just an example o how you could use it and how does the idea work, so with a little understanding of this conception you can fine-tune it on your own... It just need a small change - demoRegardless
if you type 'aw' and hit enter to select 'awesome' it creates a new tag 'aw' adds it to the selectbox and also adds 'awesome'. obviously the desired behavior is just to add 'awesome' in this case, and not to add a new tag. I think that is what @Stroll was explaining, but I can't figure out a way to prevent this issue.Welt
@Alex, I can't replicate your issue. If you just type "aw", and hit enter while "aw" is selected, then obviously it creates a new tag "aw". If you want the "awesome" tag to be selected, type "aw", then use arrows key, navigate to the "awesome" tag (highlight it) and then hit enter. Am I missing something?Regardless
@Alex, ok, sorry, you're right. Now I see what you mean :)Regardless
the authors (of select2) answer seems to answer it using a different method that was hidden in the docs: jsfiddle.net/3qkgagwk/2Welt
@Welt , It doesn't answer the question actually. Newly created tags remains in the dropdown as long as they're selected. When you unselect the new tag, it disapears from the dropdown aswell. It's the issue. You want the new tag to be sent over AJAX and stored in a database, therefore it should remain as an option to choose even if it's unselected. PS: Fixed the issue in the second example.Regardless
ah for me it works because in my implementation because the element is stored the second the comma or break to next tag is triggered. hence it is gathered via ajax when the user starts typing again should they have deselected it.Welt
O
2

The only event listener that worked for me when creating a new tag was:

.on("select2:close", function() {
 (my code)
})

This was triggered for new tags and selecting from the list. change, select2:select, select2:selecting and any others did not work.

Octahedrite answered 4/8, 2020 at 15:33 Comment(1)
To distinguish from an existing tag or a new tag I used: if(e.params.hasOwnProperty('originalSelect2Event') && e.params.originalSelect2Event.data.isNew == true)Electromyography
N
1

One more simple check will be this based on the difference in the args of the event .....

While I was dealing with this situation, I had seen this difference; that when the new element is created the event args data does not have an element object but it exists when selecting an already available option...

.on('select2:selecting', function (e) {
   if (typeof e.params.args.data.element == 'undefined') {  
      // do a further check if the item created id is not empty..
       if( e.params.args.data.id != "" ){
          // code to be executed after new tag creation
       }
   }
 })

See this picture for different condition's event log

Necrotomy answered 27/1, 2021 at 11:54 Comment(0)
P
0

Another workaround. Just insert it to the beginning:

           }).on('select2:selecting', function (evt) {

             var stringOriginal = (function (value) {
                // creation of new tag
                if (!_.isString(value)) {
                    return  value.html();
                }
                // picking existing
                return value;
            })(evt.params.args.data.text);
            ........

It relies on underscore.js for checking if it's string or not. You can replace _.isString method with whatever you like.

It uses the fact that when new term is created it's always an object.

Pyjamas answered 5/11, 2017 at 12:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.