Loading multiple tags into Select2 field using AJAX

Loading multiple tags into Select2 field using AJAX

adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

I'm using the select2 plugin for two of my columns, they both allow multiple tags, with a hidden ID behind the text shown. I can succesfully create rows, and send the data back to the server, in the form of a string of Guids, but when I try to show it in the table, I only see the string of Guids, not the labels.

I've tried a few different things to get it to work, currently I'm trying to send back back both the Id and the text, but this throws a "Requested unknown parameter" error.

I've uploaded debug data here:
http://debug.datatables.net/eqeguc

I'm not entirely sure what the correct way to go about fixing this is. I thought about editing the datatables.editor.js file to allow you to show all fields as inline editable all the time, but I don't think that's the right way either. Here's my current code:

var editor;
var SurveyDefaultGrid = SurveyDefaultGrid || {};

SurveyDefaultGrid.initGrid = function (id, tableElement) {
    editor = new $.fn.dataTable.Editor({
        ajax: {
            create: {
                type: "POST",
                url: "/surveys/surveydefaultcalculation/create/" + id,
            },
            edit: {
                type: "POST",
                url: "/surveys/surveydefaultcalculation/edit/_id_"
            },
            remove: {
                type: "GET",
                url: "/surveys/surveydefaultcalculation/delete"
            }
        },
        legacyAjax:true,
        table: tableElement,
        idSrc: "Id",
        fields: [
            {
                label: 'Element Group Reference', name: 'CompositionGroupIds', type: 'select2',
                opts: {
                    multiple: true,
                    minimumInputLength: 1,
                    ajax:{
                        url: "/api/internal/surveys/compositiongroup/search/mandate/" + id + "?format=json",
                        dataType: "JSON",
                        data: function (params) {
                            return {
                                Query: params.term, // search term
                                Page: params.page
                            };
                        },
                        processResults: function (data, page) {
                            var results = [];
                            $.each(data.Results, function (k, group) {
                                results.push({ text: group.Name, id: group.Id });
                            });
                            return {
                                results: results
                            };
                        },
                        cache: true
                    }
                    
                }
            },
            {
                label: 'Element Reference', name: 'MandateElementTypeIds', type: 'select2',
                opts: {
                    multiple: true,
                    minimumInputLength: 1,
                    ajax: {
                        url: "/api/internal/surveys/mandateelementtype/search/mandate/" + id + "?format=json",
                        dataType: "JSON",
                        data: function (params) {
                            return {
                                q: params.term, // search term
                                page: params.page
                            };
                        },
                        processResults: function (data, page) {
                            var results = [];
                            $.each(data.Results, function (k, group) {
                                results.push({ text: group.Name, id: group.Id });
                            });
                            return {
                                results: results
                            };
                        },
                        cache: true
                    }

                }
                
            },
            { label: 'Expression', name: 'Expression' },
        ],
        
    });

    editor
    .on('open', function (e, type) {
        if (type === 'inline') {
            // Listen for a tab key event when inline editing
            $(document).on('keydown.editor', function (e) {
                if (e.keyCode === 9) {
                    e.preventDefault();

                    // Find the cell that is currently being edited
                    var cell = $('div.DTE').parent();

                    if (e.shiftKey && cell.prev().length && cell.prev().index() !== 0) {
                        // One cell to the left (skipping the first column)
                        cell.prev().click();
                    }
                    else if (e.shiftKey) {
                        // Up to the previous row
                        cell.parent().prev().children().last(0).click();
                    }
                    else if (cell.next().length) {
                        // One cell to the right
                        cell.next().click();
                    }
                    else {
                        // Down to the next row
                        cell.parent().next().children().eq(1).click();
                    }
                }
            });
        }
    })
    .on('close', function () {
        $(document).off('keydown.editor');
    });

    $(tableElement).on('click', 'tbody td', function (e) {
        
        editor.inline(this, {
            submitOnBlur: true
        });             
    });

    var table = $(tableElement).DataTable({
        ajax: '/surveys/surveydefaultcalculation/data?id=' + id,
        dom: 'Bfrtip',
        columns: [
            {
                data: 'CompositionGroupIds',
                
            },
            {
                data: 'MandateElementTypeIds',
                
            },
            { data: 'Expression' }

        ],

        select: 'single',
        buttons : [
            { extend: "create", editor: editor },
            { extend: "edit",   editor: editor },
            { extend: "remove", editor: editor }
        ]
        
    });
};


This question has an accepted answers - jump to answer

Answers

  • ThomDThomD Posts: 334Questions: 11Answers: 43
    edited October 2015

    I don't know much about Select2,. but it looks like there were some syntax changes with v4.

    The last two entries in this post should help.

    http://stackoverflow.com/questions/25428361/dynamically-add-item-to-jquery-select2-control-that-uses-ajax

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    I don't think select2 is my main problem. It manages to both search and pass data back fine. It's more the way datatables displays the data that comes back.

    If I just use the Guids that it's stored as, then that's all that comes up.
    If I pass an array of {text:..., id:...} all that is shown is [object Object].

    I'm not sure what I need to pass back to the text value is shown on the table, and the tags shown when inline editing

  • ThomDThomD Posts: 334Questions: 11Answers: 43

    On the Select2 plugin docs, it shows using "label" and "value" as the key/value tags. You are using "text" and "id".

    http://editor.datatables.net/plug-ins/field-type/editor.select2

  • allanallan Posts: 63,643Questions: 1Answers: 10,492 Site admin

    Hi,

    If you reload the page, does it correctly show the text rather than the guid? If that is the case then the issue would be that the Ajax response from the edit is different from that when loading the initial data for the table.

    However, for the [Object object] part - you have:

    data: 'MandateElementTypeIds',

    Which points to an object:

            "MandateElementTyeIds": {
                "id": "302a44c4cd0a4543a388a51b010b2daf",
                "text": "test"
            }
    

    Simply using:

    data: 'MandateElementTypeIds.text',
    

    will resolve that

    Allan

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    Using

    data: 'MandateElementTypeIds.text',
    

    shows the label, but when I click into the edit window, the select2 input is empty. This is whether I use {label:..., value:...} or {id:...,text:...}. Also, I don't seem to be able to do inline editing this way?

  • ThomDThomD Posts: 334Questions: 11Answers: 43

    What version of Select2?

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    4.0.0

  • allanallan Posts: 63,643Questions: 1Answers: 10,492 Site admin

    It looks like there might be a type - in the Editor initialisation you have name: 'MandateElementTypeIds' (note that Type has a p).

    In the JSON return from your server (from the debug trace) it is: "MandateElementTyeIds": ... - no p.

    Additionally, the Editor field name should be: MandateElementTypeIds.id - i.e. the database column name that you want it to edit.

    Allan

  • jLinuxjLinux Posts: 981Questions: 73Answers: 75

    (note that Type has a p)

    Does type sometimes not come with a p? lol

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    Allan, yes I'd noticed that typo and fixed it in a later version, cheers for pointing it out.

    I apologise, I must be explaining the bug poorly. I've made a video of the specific problem and have have taken a more recent debug snapshot of the table.

    Debug: http://debug.datatables.net/ifoduf
    Video: https://youtu.be/SaRXBKxGqeI

    I illustrate the problem at the beginning of the video. Even though id's are sent down from the server

    "data": [{
            "Id": "a745715d-d23e-4a85-84db-a52b009b78ee",
            "CompositionGroupIds": null,
            "MandateId": "113e1174-530a-4063-90cd-a51b010b2c28",
            "Expression": "2",
            "MandateElementTypeIds": {
                "text": "labeltest",
                "id": "329fc28fc2c1471a904da51b010b2daf"
            }
    ...
    

    When I click on the field to put it into inline edit mode, the tag doesn't show up. The same happens in the edit window.

    After I have entered a new value into the field, it's cached by select2 and I can click in and out and the tag is shown whenever I'm in edit mode (please ignore how the label stays as labeltest after submit, this is just a mock I've sent down without doing the conversion on the server, the id is still sent though)

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    In terms of using multiple as well, I still can't get it to work either as a list of objects with 'id' and 'text' or joining the strings into id:"id1,id2,id3..." etc.

  • allanallan Posts: 63,643Questions: 1Answers: 10,492 Site admin

    Are you able to give me a link to the page please. I'll need to be able to access it in order to provide any assistance in this case I think as it is going to involve debugging.

    Allan

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    I'm not unfortunately, it's on my dev machine and it can't go on to the live site. I'd be willing to change how I'm doing it if you have advice, I can change stuff on the server to get different output and stuff.

    Can you see in general what I'm trying to do?

  • allanallan Posts: 63,643Questions: 1Answers: 10,492 Site admin

    I think so - although it is a little difficult to follow properly without being able to use the page.

    What should happen normally is that your JSON would include both the labels and the values. The labels are the values that are seen in the DataTable while the values are what Editor will edit (although it may also show the label!).

    Assuming we are using MandateElementTypeIds you would typically want your DataTable to use:

    data: 'MandateElementTypeIds.text'
    

    and Editor to use:

    name: 'MandateElementTypeIds.id'
    

    Now assuming that Select2 has a similar list of options available to it (i.e. the list of options) if you give it a specific id, it should show the label for that value. That is how the select field works, and how I think Select2 should also be working.

    What might be making it more complicated here is that your video appears to show that Select2 might be able to accept multiple tags. I don't know if that is the case or not here, but if it is, then it would need to use an array - but your data above shows an object.

    Allan

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    I am trying to get it to accept multiple tags. I've redone the server side to pass down an array, in the form of

    "MandateElementTypeIds":[
    {"id":"302a44c4-cd0a-4543-a388-a51b010b2daf","text":"2F.2.1"},
    {"id":"aea6ad0e-f483-4976-b1cf-a51b010b2daf","text":"2H.1.3"}
    ]
    

    Is this correct? Would I still want my Datatable to use

    data: 'MandateElementTypeIds.text'
    

    and Editor to use:

    name: 'MandateElementTypeIds.id'
    

    Because this doesn't seem to work. I tried looking through http://datatables.net/reference/option/columns.data to see how to handle arrays of objects, but couldn't see.

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    So, I'm using

    data: "MandateElementTypeIds[, ].text"    
    

    To display the text in the datatable, but using a similar notation for the editor throws a few different errors

    Invalid regular expression: /(^|.)select2.(?:.*.)?select2-DTE_Field_MandateElementTypeIds[,(.|$)/: Unterminated character class

    and

    The select2('val') method was called on an element that is not using Select2.

    Should I use different notation?

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    I've used

    name: 'MandateElementTypeIds', data: 'MandateElementTypeIds[, ].id'
    

    under editor fields. But this still doesn't make the tags come up, and the inline editor doesn't close after submit.

  • allanallan Posts: 63,643Questions: 1Answers: 10,492 Site admin

    Have you tried simply name: 'MandateElementTypeIds' (with no data option) for the Editor confirmation? I wonder if Select2 would handle this correctly - it depends if it wants an array of the object tags or an array of ids.

    Your approach for the DataTables display is spot on and I'll take a look locally as to why the array syntax is throwing an error - that's slightly surprising.

    Regards,
    Allan

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    Using just

    name: 'MandateElementTypeIds'
    

    is the same, nothing comes up in edit mode. Also inline edit mode complains about no knowing which field it is

    Uncaught Unable to automatically determine field from source. Please specify the field name. For more information, please refer to

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    This is what's currently happening with the setup I mentioned.

    Video: https://youtu.be/1DZOYsXDBQk

  • allanallan Posts: 63,643Questions: 1Answers: 10,492 Site admin

    Okay - the first thing we need to do is determine what values Select2 expects.

    Looking at the select2 examples ("Tagging support" specifically) if I enter $(".js-example-tags").select2('val') into the console I get an array back. So presumably it is looking for an array (although frustratingly there doesn't appear to be an example that uses an array of objects, so I'm not 100% certain).

    So let's try:

    name: 'MandateElementTypeIds[].id'
    

    in the Editor field. That will give it an array of id values.

    If you want inline editing support you'll need to use the columns.editField option like the tech note the error message links to suggests, but let's cross that bridge when we come to it.

    Allan

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    OK, I've disabled inline editing for now. It still isn't working so I've done some debugging to see what the problem might be.

    I'm getting a simple

    Uncaught TypeError: Cannot read property 'length' of null

    error in the jquery.datatables.js file when I try to create or edit an element. Its happening to val in this loop under function _fnSetObjectDataFn( mSource )

    for ( var j=0, jLen=val.length ; j<jLen ; j++ )
                            {
                                o = {};
                                setData( o, val[j], innerSrc );
                                data[ a[i] ].push( o );
                            }
    

    I worked back through and noticed where val was getting set to null, in multiGet:

    else {
          // Common value
          value = this.val();
     }
    

    this.val() was null.

    The main problem with the tags not showing up when I open the edit window still exists. I'm not 100% sure if it's related to this error.

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    Just a note: if I go back to name: 'MandateElementTypeIds' I get a similar error. where data is undefined in this loop.

    // Traverse each entry in the array getting the properties requested
    for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
        out.push( fetchData( data[j], type, innerSrc ) );
    }
    

    I think this is from data[ a[i] ] returning undefined here

    // Condition allows simply [] to be passed in
    if ( a[i] !== "" ) {
        data = data[ a[i] ];
    }
    

    An example of the data a = ["CompositionGroupIds", "text"], i = 0

    data[ a[i] ] still returns undefined even if there is a data.CompositionGroupIds

  • allanallan Posts: 63,643Questions: 1Answers: 10,492 Site admin
    Answer ✓

    I think to make any progress with being able to help here I'm going to need to set up a test page so I can experiment myself if you aren't able to give me a working test case. Unfortunately it is going to be at least a week before I have a gap to be able to do that due to a huge backlog and a release I wanted to make this week (and probably won't happen until next unfortunately).

    Allan

  • adambelshawadambelshaw Posts: 24Questions: 4Answers: 1

    That's ok,I'm going to hit my sprint deadline before that, so I think I'll end up doing it a simpler, but less usable way without select2. You've been incredibly helpful, and I definitely understand more about some of the underlying features of datatables now.

  • allanallan Posts: 63,643Questions: 1Answers: 10,492 Site admin

    I'll still look into this as I'd like to understand what is happening myself. It almost certainly won't be this week now I'm afraid - but I'll post back here when done (even if it is too late for yourself - sorry!).

    Allan

This discussion has been closed.