Not all new dynamically created tags are added

what i’m trying to achieve is that, to add new tags and get them selected and posted “as selection” to server upon clicking submit button in the form.

here the Jquery:

 $("#SelectedRoots").select2({
    tokenSeparators: [','],
    multiple: true,
    placeholder: 'Select an option',
    createTag: function (params) {
        var term = $.trim(params.term);
        if (term === '') {
            return null;
        }
        return {
            id: term,
            text: term,
            newTag: true 
        }
    },
    templateResult: function (data) {
        var $result = $("<span></span>");
        $result.text(data.text);
        if (data.newTag) {
            $result.append(" <em><strong> (New) </strong></em>");
        }
        return $result;
    },
    tags: true
}).on("select2:select", function (e) {
    if (e.params.data.tag == false) {
        return;
    }
    var select2element = $(this);
    if (e.params.data.newTag === true) {
        $.ajax({
            url: "/Roots/newRoot",
            data: { "rooting": e.params.data.text },
            dataType: "json",
            type: "POST",
            success: function (res) {
                data = {
                    "id": res.rootID,
                    "text": res.rooting,
                }
                var selection = select2element.val();
                var index = selection.indexOf(res.rooting);
                console.log("selection =", selection);
                console.log("index =", index);
                if (index !== -1) {
                    selection[index] = res.rootID.toString();
                }
                
                    $('option#' + res.rooting, select2element).attr('id', res.rootID);
                    select2element.trigger("change");
                
                
                console.log("selection after=", selection);
                console.log("index after =", index);
            },
        });
    }
           
});

what happens is that only last option is added.

console log shows the following : 
selection = (3) ["2212", "2214", "new tag"]
1:5075 index = 2
1:5084 selection after= (3) ["2212", "2214", "2216"]
1:5085 index after = 2
1:5074 selection = (4) ["2212", "2214", "new tag", "new new tag"]
1:5075 index = 3
1:5084 selection after= (4) ["2212", "2214", "new tag", "2217"]
1:5085 index after = 3

as you see, the last one has id, however previous new added tag lost the id.

i believe there should be some iteration of new added tags, but do not know to to do it. Please help.

The Select2 widget maintains its own internal data structure. I’m not sure you can “permanently” update the <option> elements it creates.

I think you should try using a JavaScript array to store the data for the Select2. In your success callback, you’ll need to update your data array with the new tag’s data, and then reinitialize the Select2 using the updated array.

Thanx @John30013, note that select2 would contain both data from server initialized with DOM and new tags. The question is how to combine both into one array?

it would be helpful if you support me with codes.

Thank you @John30013, after spending some time with your suggestion of JavaScript Array, i succeeded in getting all new tags added dynamically, however, in the selection it always showing duplicate new tags … and if i delete the very first it is ok to submit the form because it doesn’t contain id no.

this is the code:

   $("#SelectedRoots").select2({
    tokenSeparators: [','],
    multiple: true,
    placeholder: 'Select an option',
    createTag: function (params) {
        var term = $.trim(params.term);
        if (term === '') {
            return null;
        }
        return {
            id: term,
            text: term,
            newTag: true 
        }
    },
    templateResult: function (data) {
        var $result = $("<span></span>");
        $result.text(data.text);
        if (data.newTag) {
            $result.append(" <em><strong> (New) </strong></em>");
        }
        return $result;
    },
    tags: true
}).on("select2:select", function (e) {
    if (e.params.data.tag == false) {
        return;
    }
    var select2element = $(this);

    if (e.params.data.newTag === true) {
        $.ajax({
            url: "/Roots/newRoot",
            data: { "rooting": e.params.data.text },
            dataType: "json",
            type: "POST",
            success: function (res) {
                data = {
                    "id": res.rootID,
                    "text": res.rooting,
                }
                var selection = select2element.val();
                
                if ($('#SelectedRoots').find("option[value='" + res.rootID + "']").length) {
                    $('#SelectedRoots').val(res.rootID).trigger('change');
                } else {
                    var option = new Option(res.rooting, res.rootID, true, true);
                    $('#SelectedRoots').append(option).trigger('change');
                    console.log("selection =", selection);
                }
            },
        });
    }
});

new tag

what duplicates the new tag?? i’m struggling in resolving this, what is the missing part?

Hi, @M.G,

I really don’t know why the new tag is duplicated. As I noted in my previous reply, you are trying to modify the <option> elements that Select2 creates for your dynamic tags. Those <option> elements are connected to Select2’s internal data structure (note the data-select2-id attribute in those <option>s). I don’t know how the internals of the Select2 widget work, but my guess is that your modifications are somehow causing Select2 to lose track of the <option> it already created when you trigger the change event, and so it creates another <option> element.

That is why I suggested that you use a JavaScript array to supply data to the Select2 (instead of initializing the Select2 from the HTML <select>'s <option>s; you will have full control over that array, and when you re-initialize the Select2 widget, it will only display the data that’s in the JavaScript array.

So, your initial HTML should look something like this:

<select id="SelectedRoots">
</select>

And your JavaScript should look something like this:

// Specify initial data for the Select2.
var rootsData = [
  { id: 2000, text: "root1" },
  { id: 2001, text: "root2" }, 
  // ...
];
var updateRootsData = function(e) {
  if (e.params.data.tag === false) {
    return;
  }
  var select2element = $(this);

  if (e.params.data.newTag === true) {
    $.ajax({ 
      // ... all the other AJAX options from your code above.
      success: function(res) {
        var selectedRootIndex = rootsData.findIndex(function(r) { return r.id === res.rootID; });
        if (selectedRootIndex > -1) {
          rootsData[selectedRootIndex].selected = true;
        } else {
          rootsData.push({ id: res.rootID, text: res.rooting, selected: true });
        }
        initializeSelect2();
      }
    });
  }
};

var initializeSelect2 = function() {
  $('#SelectedRoots').select2({
    data: rootsData,
    // ... all the other initialization options from your code.
  }).on('select2:select', updateRootsData);
};

initializeSelect2();

Note that I haven’t tested this code, but I think the general idea of it is correct.

John, actually i failed to apply your suggestion, however, succeeded in doing it in another way. as i mentioned previously the first tag is “ID-less” as it is the original tag. therefore, after stuggeling in applying your seggestion, i opted to do it in a way to delete/remove the first tag. the result is very satisfactory.

the new line i added is just above Ajax as follows:

               $('#SelectedRoots').find("option[value='" + e.params.data.text + "']").remove();
               $ajax({ .... })
1 Like

Hi, M.G.,

Great! I’m glad you were able to solve the problem.

Good luck with your project!