8
votes

I implemented a tagging system where you can choose from existing tags or add new tags. After a new tag has been selected it will persisted using an AJAX call.

For achieving this I use the callback createTag and the event select2:select. Because I like to create the tag only when it is selected I do an AJAX call for this if the event select2:select gets triggered.

The problem is that I need to update the already created option of select2 with the ID I get from persisting my new tag to the database. What's the cleanest solution for this?

Here's what I have:

$('select.tags').select2({
     tags: true,
     ajax: {
         url: '{{ path('tag_auto_complete') }}',
         processResults: function (data) {
             return {
                 results: data.items,
                 pagination: {
                     more: false
                 }
             };
         }
     },
     createTag: function (tag) {
         return {
             id: tag.term, // <-- this one should get exchanged after persisting the new tag
             text: tag.term,
             tag: true
         };
     }
 }).on('select2:select', function (evt) {
     if(evt.params.data.tag == false) {
         return;
     }

     $.post('{{ path('tag_crrate_auto_complete') }}', { name: evt.params.data.text }, function( data ) {
        // ----> Here I need to update the option created in "createTag" with the ID
        option_to_update.value = data.id;

     }, "json");
 });
2
Have you tried triggering a change event once the tag is created?BuddhistBeast
@BuddhistBeast should this help me exactly? If I listen to this event my ID is already gone? Or should I listen to the change event instead of the select event?TiMESPLiNTER

2 Answers

5
votes

My problem was that I did not add the new tag as an <option> tag to the native select field.

This is necessary because select2 checks for the values set trough select2.val(values) if an <option> tag with this value does exist. If not select2 silently throws the value out of the array and sets the array of values which have a corresponding option tag in the underlying select field.

So this is how it works correct now (for select2 4.0.x):

$('select.tags').select2({
     tags: true,
     ajax: {
         url: '{{ path('tag_auto_complete') }}',
         processResults: function (data) {
             return {
                 results: data.items,
                 pagination: {
                     more: false
                 }
             };
         }
     },
     createTag: function (tag) {
         return {
             id: tag.term,
             text: tag.term,
             tag: true
         };
     }
 }).on('select2:select', function (evt) {
     if(evt.params.data.tag == false) {
         return;
     }

     var select2Element = $(this);

     $.post('{{ path('tag_crrate_auto_complete') }}', { name: evt.params.data.text }, function( data ) {
        // Add HTML option to select field
        $('<option value="' + data.id + '">' + data.text + '</option>').appendTo(select2Element);

        // Replace the tag name in the current selection with the new persisted ID
        var selection = select2Element.val();
        var index = selection.indexOf(data.text);            

        if (index !== -1) {
            selection[index] = data.id.toString();
        }

        select2Element.val(selection).trigger('change');

     }, 'json');
 });

The minimal AJAX response (JSON format) has to look like this:

[
    {'id': '1', 'text': 'foo'},
    {'id': '2', 'text': 'bar'},
    {'id': '3', 'text': 'baz'}
]

You may add additional data to each result for let's say own rendering of the result list with additional data in it.

0
votes

Just to update:

The new syntax is

e.params.args.data.id

not

e.params.data.id