How to display Datatables Editor Select2 field preselections?

How to display Datatables Editor Select2 field preselections?

lthammlthamm Posts: 13Questions: 2Answers: 0

Hi,

I am working with the Editor and a Select2 field and I load the options via ajax, which works just fine. But I am struggling to get the current of the cell labeled as already being selected.

What I have done:
In order to use Select2 as a field I downloaded the Editor plugin and included it together with the Select2 original files.
I then added a field to the editor that has the type "select2". Within the option i specify that multiple selections are allowed and specify an ajax source.
This ajax reuqest is being made when I open up the Editor for that row.

var editor = new $.fn.dataTable.Editor({
      ajax: {
        url: "/getData",
        type: 'POST'
      },
      table: '#result-table',
      fields: [
        {
          label: 'Tags',
          name: colMappings['Themen'],
          type: "select2",
          opts: {
            "multiple": true,
            ajax: {
              url: '/getTags',
              dataType: 'json',
              initialValue: true
            }
          });

The request sends the current value of that field and intitalValue=true as get parameters.
On the server I then format my response according to the Select2 datatype documentation (https://select2.org/data-sources/formats).
Not that the response has to be wrapped into results and that results is an array.

{
    "results": 

        [
            {"id": tag, "text": tag},
            {"id": tag2, "text": tag2}

        ]



}

Based on the current value I receive via the Ajax request I want to label some options as preselections, so the user does not have to enter them again whenever he wants to add or delete a tag.
According to the Select2 doc I can simply add the selected: true tag.

    {
        "results": 

            [
                {"id": tag, "text": tag, "selected": True},
                {"id": tag2, "text": tag2}

            ]



    }

Yet this hasn't been working for me. The selection displays all options correctly but no option is preselected.

1) Maybe this process could be included into the documentation as right now it is rather unspecific.
2) How do I get the selections preselections to work?

Thank you very much!

Answers

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    I guess Select2 expects "selected" to be true and not True.

    JS is case sensitive.

  • lthammlthamm Posts: 13Questions: 2Answers: 0
    edited March 2020

    Thanks for your reply. Sorry for the confusion, but what you see is the construction within the backend, not the response.

    I use json.dumps within python to transform the Boolean to json, so the response has a "selected": true, which I just checked again.

  • lthammlthamm Posts: 13Questions: 2Answers: 0
    edited March 2020

    I've now also tried to send the true as a string, which also did not work. This leaves me kind of clueless.

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    I never use Select2 with data tables. I only use "Select" and "Selectize". My favorite is actually "Selectize".
    https://github.com/selectize/selectize.js/blob/master/docs/usage.md

    I remember trying Select2 initially. I quickly learned to hate it :)

  • lthammlthamm Posts: 13Questions: 2Answers: 0
    edited March 2020

    Your recommendation looks great! So thanks for suggesting it.
    But I am already using select2 in other places within the same project and so far it has been working fine.

    I'd really like to not introduce another dependency and ui. But if there aren't any ideas how to figure the select2 out, I appreciate having the selectize option as a backup.

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406
    edited March 2020

    Check it out on Stack Overflow as well please. You might get help there as well. So many people are using Select2.
    Selectize is really light weight, don't worry. But I understand why you don't like the idea ...

  • lthammlthamm Posts: 13Questions: 2Answers: 0

    I'll try one more thing tomorrow: Using the data from the API to build the Select2 without the Editor. Then I'll know for sure if I have a problem with the editor or with select2.
    If it's a problem with the editor maybe some in the forum can help, if it's not I'll ask at stackoverflow or just switch to selectize (which I might use right from the beginning at other projects).

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    Sounds like you're doing the right thing! And if you believe that Editor causes the issue I recommend you try to address this to @allan or @colin. Allan wrote most or all of this.

  • lthammlthamm Posts: 13Questions: 2Answers: 0
    edited March 2020

    So without taking into account the editor:

    This also does not respect the preselections:
    $("#tag1").select2({ ajax: { url: "/getTags" type: "get", dataType: 'json' } });

    But doing this:
    $.getJSON("/getTags", function(data) { $("select#tags").select2({ data: data["results"] }); });

    Works fine!

    So this seems to be an issue with select2, there are multiple issues on their github on this, e.g.:
    https://github.com/select2/select2/issues/5679

    There they indicate that "selected: true" doesn't actually preselect the items, which is not true when you use the "data:" instead of the ajax method.
    With respect to Editor they indicate that there should be an option to manually select the options based on the ajax response - is there any way to do it? Or could I possibly have the getJSON call when clicking edit and then pass it into the select2 constructor?

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    Interesting what Kevin Brown writes in the link you quote:
    "The server response only indicates that it's selected in the dropdown that shows the results, it does not "pre-select" it for you on the front end. You need to actually select it within the dropdown in order for that to work.

    I believe this is ultimately a datatables editor issue if it does not provide a way to pre-select items in a select box, much less Select2."

    Sounds plausible to me because I tested the same thing with selectize right now using "items" (see above). I could see the "items" are correctly passed as part of the conf object but just like with select2 they are being ignored by the Editor field-type plug in. I checked this file https://editor.datatables.net/plug-ins/field-type/editor.selectize
    So Kevin Brown seems to be right

    You can take a look at this for select2 as well and check:
    https://editor.datatables.net/plug-ins/field-type/editor.select2

  • lthammlthamm Posts: 13Questions: 2Answers: 0

    Well, the weird thing is that for Select2 it also does not work when I do it with the ajax option within the constructor, but only when I get the data beforehand and pass it into the data option of the constructor. So it does not seem to be an Editor problem entirely.
    But thanks for checking that out with selectize as well, which means that switching also wouldn't be an option for now.

  • kthorngrenkthorngren Posts: 20,144Questions: 26Answers: 4,736

    I haven't tried using the Select2 ajax option to fetch the options. I don't know how this plays into the Editor events like the initEdit event. If initEdit
    follows after the ajax response then you may be able to use something like $(select).val("3").trigger("change"); to set the default vlaue. The plugin example has this:

    {
             "label": "Priority:",
             "name": "priority",
             "type": "select2",
             "options": [
                 { "label": "1 (highest)", "value": "1" },
                 { "label": "2",           "value": "2" },
                 { "label": "3",           "value": "3" },
                 { "label": "4",           "value": "4" },
                 { "label": "5 (lowest)",  "value": "5" }
             ]
    },
    

    If you wanted option 3 to be the selected option you could do something like this:

      editor.on('initEdit', function(e, node, data, items, type) {
        var field = editor.field('priority');
        
        var select = $(field.node()).find('select');
        $(select).val("3").trigger("change");
    
      });
    

    I don't have a testbed setup to try it. But you may be able to work something out with this. Let us know.

    Kevin

  • lthammlthamm Posts: 13Questions: 2Answers: 0
    edited March 2020

    Thanks for taking a look Kevin! Unfortunately this did not work, I looked into the Select2 doc and checked why this would happen and actually found an answer to it:

    For Select2 controls that receive their data from an AJAX source, using .val() will not work. The options won't exist yet, because the AJAX request is not fired until the control is opened and/or the user begins searching. This is further complicated by server-side filtering and pagination - there is no guarantee when a particular item will actually be loaded into the Select2 control!
    https://select2.org/programmatic-control/add-select-clear-items

    They suggest just to manually append the options to the select. The hint with the "initEdit" event helped me a lot to actually do that.

    So in order to preselect ajax sourced data:
    1) Initialize the field within the editor
    var editor = new $.fn.dataTable.Editor({
    //....
    fields: [{
    {
    label: 'Target',
    name: 'target',
    type: "select2",
    opts: {
    'multiple': true,
    ajax: {
    url: '/getData',
    dataType: 'json'
    }
    }
    }
    }]

          // ....
        })
    

    2) Use the initEdit event to manually append the correct options:
    (Note: Your server has to return "selected": true for every option based on the rows key.

        editor.on('initEdit', function(e, node, data, items, type) {
        
        
          // [APPEND PRESELECTED OPTIONS TO SELECT2]
        
          // Find the correct select
          var field = editor.field('target');
          var select = $(field.node()).find('select');
        
          // Select the key for the row so we can send it to the server and
          // Return "selected : true" for the correct options
          var rowKey = data[colMappings["Kanalid"]]
        
        
          // Get the selected options
          $.ajax({
            type: 'GET',
            url: '/getData',
            dataType: 'json',
            data: {
              "forKey": rowKey
            }
          }).then(function(data) {
        
            // create the option and append to Select2
            data["results"].forEach(function(tag) {
        
              if (tag.selected) {
                let option = new Option(tag.id, tag.text, true, true);
                select.append(option).trigger('change');
              }
        
            })
        
            // manually trigger the `select2:select` event
            // Don't know if I have to do it, but it's in the docs
            select.trigger({
              type: 'select2:select',
              params: {
                data: data
              }
            });
          });
        });
    

    You can probably just append all options to the select2 there and avoid the redundant ajax call if you don't need the ajax connection for select2.

    Edit: I have no idea what's happening with the code formatting for block 1 but seem unable to change that.

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    I think there is a really easy solution for this. I am surprised we haven't thought about it earlier...

    What are "preselected or default options"? They are nothing but field content, aren't they? I mean the options array itself contains labels and values. So just use the values of your "preselected or default options" and use them as default field content. That should work for any select plugin.

    Here is an example for a holiday calendar. Depending on the user's state you preselect public holidays in that calendar. Works like a charm ...

    }, {
        label: lang === 'de' ? 'Feiertagskalender:' : 'Holiday Calendar:',
        name: "fixed.holiday_calendar",
        type: "select",
        multiple: true,
        def: function () {
            if ( userState === "NRW") {
                return ["2", "2a", "2b"];
            } else if ( userState === "Bayern" ) {
                return ["2", "2a", "2b", "2d", "2e"]
            } else {
                return ["2"];
            }
        },
        separator: '/',
        options: [   
            { label: "Target2 Feiertage", value: '1' },
            { label: "Bundeseinheitliche Bankfeiertage", value: '2' },
            { label: " - plus Fronleichnam", value: '2a' },
            { label: " - plus Allerheiligen", value: '2b' },
            { label: " - plus Reformationstag", value: '2c' },
            { label: " - plus Dreikönigstag", value: '2d' },
            { label: " - plus Mariä Himmelfahrt", value: '2e' }, 
            { label: " - plus Buß- und Bettag", value: '2f' },
        ]
    }, {
    

    User from NRW:

    Alternatively you can use events like "open" etc. or even "dependent" and set the field content dynamically - for any field not only for select fields.

  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin

    Hi,

    In the Select2 integration plug-in for Editor you'll find the following code:

                        var addOption = function ( option ) {
                            if ( conf._input.find('option[value="'+option.id+'"]').length === 0 ) {
                                $('<option/>')
                                    .attr('value', option.id)
                                    .text( option.text )
                                    .appendTo( conf._input );
                            }
                        }
    

    I believe the issue you are seeing is related to that. Rather than passing the raw data straight to Select2 (although given the bug you mentioned, it is questionable if that would resolve it anyway) we populate the option tags directly and Select2 reads them. So that function could be expanded thus:

                        var addOption = function ( option ) {
                            if ( conf._input.find('option[value="'+option.id+'"]').length === 0 ) {
                                $('<option/>')
                                    .attr('value', option.id)
                                    .text( option.text )
                                    .prop( 'selected', option.selected )
                                    .appendTo( conf._input );
                            }
                        }
    

    That will mean that the selected attribute will reflect the option for your object. Select2 should then see that and use it.

    Regards,
    Allan

  • lthammlthamm Posts: 13Questions: 2Answers: 0

    Hi Allan,

    thank you! This would be a helpful addition in general to reflect the select2 datatype, but as they mention this might not be displayed in the frontend right from the start for ajax sourced data.

    @rf1234
    This is a smart solution! But I wonder if it is actually possibly to adapt that to my use case, as def defines preselections generally for all fields. I need my selections to be based on the row that I am editing (because I want it to show the state of the cell being edited).

    In case my last post left you wondering: Selecting the options in the on edit event works for my use case.

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406
    edited April 2020

    "But I wonder if it is actually possibly to adapt that to my use case, as def defines preselections generally for all fields. I need my selections to be based on the row that I am editing (because I want it to show the state of the cell being edited)."

    I think I don't understand your use case well enough. The preselection actually doesn't make much sense if you edit a record - because that record will have values for the select field already - and those values ARE the preselection.

    If you just want to make a preselection of the select field regardless of its previously saved content you can make that of course. You can overwrite the field content dynamically on "select" of a row for editing or even "dependent" on the values of other fields of the form you are editing.

    So can you explain a little better what your use case actually is please. Happy to get back to you with an example for dynamic field value setting afterwards.

  • ali@tableali@table Posts: 2Questions: 1Answers: 0
    edited March 2021

    I need live search in "modal create" or "modal edit".
    Maybe I have a lot of data in the field. for example "Group" for choose a User

  • colincolin Posts: 15,118Questions: 1Answers: 2,583

    Editor 2.0 has a DataTable type - which does provide functionality like this. See example here.

    Colin

This discussion has been closed.