Custom field type plugins and inline editing

Custom field type plugins and inline editing

pwoopwoo Posts: 1Questions: 1Answers: 0

I'm currently putting together a datatable containing standard text fields and a custom field plugin that displays a form text input + dropdown list on inline edit.

Using inline edit on the standard text fields work correctly -- I can see the callback function that I've assigned to the ajax option is being called, and the new value is then displayed when the editor is closed. This doesn't seem to be the case with the custom plugin -- the callback is never called. In addition, assigning a dummy return value to the get function does not seem to result in it being displayed when the inline editor is closed. Have I misinterpreted how it works? I've placed an example of what has been done below.

        _fieldTypes.power = {
            create: function (field, id) {
                var that = this;

                field._enabled = true;
                field._input = $(
                '<div class="input-group">' +
                '<input type="text" class="form-control" aria-label="...">' +
                '<div class="input-group-btn">' +
                '<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-menu-down"></span></button>' +                                     
                '<ul class="dropdown-menu dropdown-menu-right">' +
                '<li name="absolute" value="0"><a href="#">Absolute</a></li>' +
                '<li name="relative" value="1"><a href="#">Relative</a></li>' +
                '</ul>' +
                '</div><!-- /btn-group -->' +  
                '</div><!-- /input-group -->)')[0];
                
                $('ul li', field._input).click(function (e) {                          
                    
                    e.preventDefault();
                });

                return field._input;
            },
        get: function (field) {
                return "hello world!";
            },
        set: function (field, val) {
            }
        };

    })(jQuery, jQuery.fn.dataTable);  
    
    editor = new $.fn.dataTable.Editor({
        ajax: function (method, url, d, successCallback, errorCallback) {
            var output = {data: []};

            if (d.action === 'edit') {
                // Update each edited item with the data submitted
                $.each(d.data, function (id, value) {
                    row = $('#wo').DataTable().row('#' + id).data();
                    $.extend(row, value);
                    output.data.push(row);
                });
            }

            // Show Editor what has changed
            successCallback(output);
        },
        table: "#wo",
        fields: [{
            name: "name"
            }, {
            name: "power",
            type: "power"
            }
        ]
    });             

Answers

  • drewturkdrewturk Posts: 27Questions: 8Answers: 0

    I have the same problem with my custom autocomplete input...any resolutions at all?

  • allanallan Posts: 61,885Questions: 1Answers: 10,140 Site admin

    There shouldn't be any difference between how a field works inline compared to the main form. If it works okay it should work okay inline - if that is not the case, can you link to a test page showing the issue so it can be debugged please?

    Thanks,
    Allan

  • drewturkdrewturk Posts: 27Questions: 8Answers: 0

    Thanks Allan,
    Unfortunately I can not provide a link to that page, as it would require authentication, (you probably get that a lot). I do have a debug for it, though I don't know how much that will help: http://debug.datatables.net/urenic

    Basically here is my custom field type:

        _fieldTypes.autocomplete = {
            // Create the HTML mark-up needed for input and add any event handlers needed
            create: function (field) {
                field._enabled = true;
                var input = $('<div><input type="text" /><input type="hidden" /></div>');
                field._input = input[0];
    
                var acInput = input.children('input[type=text]');
                acInput.cbtAutocomplete(field.acOpts);
                acInput.on("autocompletesearch", function (event, ui) {
                    acInput.autocomplete("option", "appendTo", ".reveal-modal.open");
                });
                acInput.on("autocompleteselect", function (event, ui) {
                    if (!ui.item.ignore) {
                        acInput.val(ui.item.label);
                        input.children('input[type=hidden]').val(ui.item.id);
                    }
                });
                return field._input;
            },
    
            // Get the field value
            get: function (field) {
                var values = {};
                values.value = $(field._input).children('input[type=text]').val();
                values.id = $(field._input).children('input[type=hidden]').val();
                return values;
            },
    
            // Set the field value from DT data
            set: function (field, val) {
                var render = val != '' ? field.acRender(val) : val;
                var id = val != '' ? val.id : val;
                $(field._input).children('input[type=text]').val(render);
                $(field._input).children('input[type=hidden]').val(id);
            },
    
            // Enable the field
            enable: function (field) {
    
            },
    
            // Disable the field
            disable: function (field) {
    
            }
        };
    

    Here is my editor instance:

       var valuesEditor = new $.fn.dataTable.Editor({
            table: '#udidValues',
            // modify editor data object
            ajax: function (method, url, data, success, error) {
                console.log('ajax');
                if (data.action === 'create') {
                    // we need to add unique id
                    var dateKey = +new Date();
                    data.data[0].id = dateKey;
                    valuesDataTable.DataTable().row.add(data.data[0]);
                    success(valuesDataTable.DataTable().data());
                }
                else if (data.action === 'edit') {
                    var objKey = Object.getOwnPropertyNames(data.data)[0];
                    data.data[objKey].id = objKey;
                    var valueMapping = {'value': 'name'};
                    // change key from 'id' to 'name' for rendering
                    data.data[objKey].moveToClient = _.reduce(data.data[objKey].moveToClient, function(result, value, key) {
                        key = valueMapping[key] || key;
                        result[key] = value;
                        return result;
                    }, {});
                    var newData = { data: [] };
                    newData.data.push(data.data[objKey]);
                    success(newData);
                }
                else if (data.action === 'remove') {
                    valuesDataTable.DataTable().row(data.data).delete();
                    success(valuesDataTable.DataTable().data());
                }
            },
            idSrc: 'id',
            fields: [
                {
                    label: 'Description',
                    name: 'description'
                },
                {
                    label: 'Value',
                    name: 'value'
                },
                {
                    label: 'Move to Account/Division',
                    labelInfo: '(Optional)',
                    name: 'moveToClient',
                    type: 'autocomplete',
                    acRender: function (data) {
                        return data.name
                    },
                    acOpts: {
                        search: ['anyclient']
                    }
                }
            ]
        });
    

    I am enabling inline edit:

        valuesDataTable.on('click', 'tbody td:not(:last-child)', function (e) {
            valuesEditor.inline(this/*, { submit: 'allIfChanged' }*/);
        });
    
    

    I am trying to submit from the autocomplete input upon using 'enter' key, as it does with all other inputs. I would expect the submit from that action would allow the ajax to be called and subsequently perform the "data.action === 'edit'" portion of the above logic. But that never happens, it only works for regular inputs, not the custom field type I implemented.

    Hoping that made any sense for you. Thanks.

  • drewturkdrewturk Posts: 27Questions: 8Answers: 0

    Any ideas? Thanks

  • allanallan Posts: 61,885Questions: 1Answers: 10,140 Site admin

    Sorry for the delay in replying - I completely missed your first reply!

    What is the AutoComplete library you are using? I'm wondering if it might be swallowing the return key.

    I've just tried my jQuery UI AutoComplete integration for Editor and it appears to take the return key okay when entering a value inline.

    Internally Editor does this for the return key handling:

        $(document).on( 'keydown'+namespace, function ( e ) {
            var el = $(document.activeElement);
            var name = el.length ? el[0].nodeName.toLowerCase() : null;
            var type = $(el).attr('type');
            var returnFriendlyNode = name === 'input';
    
            if ( that.s.displayed && opts.onReturn === 'submit' && e.keyCode === 13 && returnFriendlyNode ) { // return
                e.preventDefault();
                that.submit();
            }
    

    i.e. it will only work on input elements (which you have) and it needs to be able to see the keydown event. Is that isn't propagated up the DOM tree then it wouldn't be able to see it.

    Allan

This discussion has been closed.