2
votes

In select2 I have tags loaded by AJAX, if the tag is not found in the db then the user has the option to create a new one. The issue is that the new tag is listed in the select2 box as a term and not as the id (what select to wants - especially becomes a problem when loading the tags again if the user wants to update since only the term and not the id is stored in the db). How can I, on success of adding the term, make it so that select2 recieves the ID and submits the ID instead of the tag name/term?

$(document).ready(function() {
var lastResults = [];
$("#project_tags").select2({
    multiple: true,
    placeholder: "Please enter tags",
    tokenSeparators: [","],
    initSelection : function (element, callback) {
        var data = [];
        $(element.val().split(",")).each(function () {
            data.push({id: this, text: this});
        });
        callback(data);
    },
    ajax: {
        multiple: true,
        url: "framework/helpers/tags.php",
        dataType: "json",
        data: function(term) {
            return {
                term: term
            };
        },
        results: function(data) {
            return {
                results: data
            };
        }
    },
    createSearchChoice: function(term) {
        var text = term + (lastResults.some(function(r) {
            return r.text == term
        }) ? "" : " (new)");
        return {
            id: term,
            text: text
        };
    },
});
$('#project_tags').on("change", function(e) {
    if (e.added) {
        if (/ \(new\)$/.test(e.added.text)) {
            var response = confirm("Do you want to add the new tag " + e.added.id + "?");
            if (response == true) {
                alert("Will now send new tag to server: " + e.added.id);
                $.ajax({
                    url: 'framework/helpers/tags.php',
                    data: {
                        action: 'add',
                        term: e.added.id
                    },
                    success: function(data) {

                    },
                    error: function() {
                        alert("error");
                    }
                });
            } else {
                console.log("Removing the tag");
                var selectedTags = $("#project_tags").select2("val");
                var index = selectedTags.indexOf(e.added.id);
                selectedTags.splice(index, 1);
                if (selectedTags.length == 0) {
                    $("#project_tags").select2("val", "");
                } else {
                    $("#project_tags").select2("val", selectedTags);
                }
            }
        }
    }
});

});

Heres part of the switch that does the adding

case 'add':
    if (isset($_GET['term'])) {
        $new_tag = escape($_GET['term']);
        if (Nemesis::insert('tags', 'tag_id, tag_content', "NULL, '{$new_tag}'")) {
            // we need to send back the ID for the newly created tag
            $search = Nemesis::select('tag_id', 'tags', "tag_content = '{$new_tag}'");
            list($tag_id) = $search->fetch_row();
            echo $tag_id;
        } else {
            echo 'Failure';
        }
        exit();
    }
    break;

UPDATE: I've done a bit of digging, and what confuses me is that the select2 input does not seem to store the associated ID for the tag/term (see below). I know I could change the attribute with the success callback, but I don't know what to change!

enter image description here

1
What do you mean "doing something screwy here"? What exactly is happening? In your data option, try data: { term: e.added.id, action: 'add' } and then remove the ?action=add&term=' + e.added.id + '' portion of the url option.mathewbergt
Yea exactly.. I did that but reverted to the way I have it now because in devtools for chrome you can clearly see nothing is being added to the end of the url and consequently the db (just posts to tags.php). However it works in the above part.Alex
Well you are using type: "POST" which means the variables will NOT be added to the end of the URL. Instead, in Chrome Dev Tools look under the 'Headers' tab of the ajax call and expand the 'Form Data' section to view the term and action variables passed in the POST. If you want to see the variables in the URL, use type: "GET". Also, it looks like in your PHP code you are testing whether the request is of type GET, so you will want to make your AJAX call and that logic match.mathewbergt
@404 here is the final class: pastebin.com/3jfS4tVGAlex
Here is the class setup: pastebin.com/PB1H2C1rAlex

1 Answers

5
votes

As you have said, you can replace that value, and that is what my solution does. If you search the Element Inspector of Chrome, you will see, bellow the Select2 field, an input with the id project_tags and the height of 1.

The weird thing is that the element inspector of Chrome does not show you the values of the input, as you can see below:

enter image description here

However, you do a console.log($("#project_tags").val()) the input has values (as you see in the image).

So, you can simply replace the text of the new option by the id, inside the success function of the ajax call placed within the $('#project_tags').on("change") function. The ajax call will be something like:

$.ajax({
    url: 'framework/helpers/tags.php',
    data: {
        action: 'add',
        term: e.added.id
    },
    success: function(tag_id) {
        var new_val = $("#project_tags")
                        .val()
                        .replace(e.added.id, tag_id);
        $("#project_tags").val(new_val);
    },
    error: function() {
        alert("error");
    }
});

Please be aware that this solution is not bullet proof. For example, if you have a tag with the value 1 selected, and the user inserts the text 1, this will cause problems.

Maybe a better option would be replace everything at the right of the last comma. However, even this might have cause some problems, if you allow the user to create a tag with a comma.

Let me know if you need any more information.