DataTable and inline Editor without database

DataTable and inline Editor without database

arnorbldarnorbld Posts: 110Questions: 20Answers: 1

Hi guys,

I have a situation where I have a Data Table that is filled with data from a web service without any database on our end.

Data loads fine into the DataTable via AJAX and the data comes in formatted correctly. But I'm having a problem implementing the Editor. When I click on a cell the editor comes up. I can edit the field but then nothing happens. If I click somewhere else on the page the editor field closes but the table is not updated. Also the editor now no longer responds to clicks on any cells. No errors are reported in the console.

I'm using local storage for the data based on what I have found in examples and forum posts. This is the editor Editor code I have:



function setupEditor() { editor = new jQuery.fn.dataTable.Editor({ table: '#task-and-po-table', fields: [ {"label": "Job", "name": "JOBNUM"}, {"label": "Vendor", "name": "VENDORNUMBER"}, {"label": "Name", "name": "VENDORNAME"}, {"label": "Task Num", "name": "SEQUENCE"}, {"label": "Start Date", "name": "STARTDATE"}, {"label": "End Date", "name": "ENDDATE"}, ], ajax: function ( method, url, d, successCallback, errorCallback ) { console.log('Editor . Ajax'); var output = { data: [] }; if ( d.action === 'edit' ) { jQuery.each( d.data, function (id, value) { value.DT_RowId = id; jQuery.extend( combinedList[ id ], value ); output.data.push( combinedList[ id ] ); } ); } localStorage.setItem( 'combinedList', JSON.stringify(combinedList) ); successCallback( output ); } }); // Activate an inline edit on click of a table cell jQuery('#task-and-po-table').on('click', 'tbody td:not(:first-child)', function (e) { console.log('editor.inline'); editor.inline(this); }); }

Even though the editor doesn't activate, the console.log in the click executes.

I will probably go with setting up a SQL table for this and see if I can make that work. But I really would like to understand where I'm going wrong. I'm missing something. I just noticed that the console.log('Editor . Ajax') never shows up...

Thanks in advance for any advice!

Answers

  • allanallan Posts: 61,740Questions: 1Answers: 10,111 Site admin

    In the first instance try:

    editor.inline(this, {
      onBlur: ‘submit’
    });
    

    That will cause an automatic submission when you click elsewhere. Otherwise the submission is just cancelled. Without the onBlur option you’d need to press return to submit the field rather than click elsewhere.

    Allan

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    Thanks! Now, if I hit Tab in the entry the focus moves out, but it does not close the entry and update the data. In fact, now I can't get it to remove the entry at all.

  • allanallan Posts: 61,740Questions: 1Answers: 10,111 Site admin

    What happens if you click somewhere else on the page? Editor's inline editing doesn't automatically handle the tab key - you'd need KeyTable or something like that, but that might not be suitable in this case? If you could link to a page showing the issue that would be great.

    Thanks,
    Allan

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    Unfortunately, this is all local, not available online anywhere.

    What happens after adding the onblur:'submit' is that it no longer closes/hides the entry. Prior to adding that it would close it, but the changes would not show in the table and after the first entry showed up, it never happened again.

    I've moved this over to using a SQL table as a temp/cache table while I try to sort this out.

    If I can't get that to work, I'll move this to a test site online where you could take a look.

    Thanks for the help :)

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    So I implemented this using SQL today. Same thing! The Ajax is just never called.


    console.log('Editor Ajax URL: ' + EditorAjaxURL); editor = new jQuery.fn.dataTable.Editor( { table: '#test-table', ajax: { url: EditorAjaxURL }, fields: [ { "label": "Job", "name": "jobnum" }, { "label": "Vendor", "name": "vendornumber" }, { "label": "Name", "name": "vendorname" }, { "label": "Task #", "name": "sequence" }, { "label": "Start Date", "name": "startdate" }, { "label": "End Date", "name": "enddate" } ] });

    The EditorAjaxURL is correct and if I click on it in the console it takes me to the PHP script.

    I added a submit button to the edit field:

    jQuery('#test-table').on( 'click', 'tbody td:not(:first-child)', function (e) {
        editor.inline( this, {
            buttons: { label: 'Save', fn: function () {
                console.log('submitting data');
                this.submit();
            }
            }
        } );
    } );
    

    and the "submitting data' appears in the console, but then nothing at all. The entry and the button just sit there. If I click outside they are hidden, but then if I click back on any cell, the entry and button never show up until I reload the page.

    There are no errors shown in the console.

    This is inside the Joomla framework, (been working on a large set of components/modules/plugins for a client for the past few years) but I have not had any issues with DataTables once I load the correct versions of jQuery and jQuery.ui etc.

    I will try to create a simple sample outside the Joomla environment over the weekend and see where that gets me.

  • allanallan Posts: 61,740Questions: 1Answers: 10,111 Site admin

    I’m at a bit of a loss I’m afraid - what you have there looks absolutely fine. If you are able to setup an example, please do send it over as I’d like to understand what is going wrong.

    Allan

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    Yes, it has me stomped! I switched over to the non-minified editor js file and I'm adding some console.log to the submit method to see if I can track down if it's failing somewhere or what the heck is going on! Implementing DataTables has been easy and straight forward and I have several of them working now in the Joomla environment.

    If I can't find anything I will try to duplicate this in a non-Joomla environment on a site that I can then upload for you to take a look at. This really is perplexing, but that's why we get paid the big bucks, right?<g> Have a great weekend!

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    I have found where it stops. In the datatables.editor.js file this is where It stops:

    Editor.prototype._submit = function ( successCallback, errorCallback, formatdata, hide )
    {
        console.log('AB 2021-01-08:  Editor.prototype._submit')
    
        var that = this;
        var i, iLen, eventRet, errorNodes;
        var changed = false, allData = {}, changedData = {};
        var setBuilder =  DataTable.ext.oApi._fnSetObjectDataFn;
        var dataSource = this.s.dataSource;
        var fields = this.s.fields;
        var editCount = this.s.editCount;
        var modifier = this.s.modifier;
        var editFields = this.s.editFields;
        var editData = this.s.editData;
        var opts = this.s.editOpts;
        var changedSubmit = opts.submit;
        var submitParamsLocal;
    
        // First - are any of the fields currently "processing"? If so, then we
        // want to let them complete before submitting
        if (this._noProcessing(arguments) === false) {
            console.log('AB 2021-01-08:  this._noProcessing is false');
            return;
        }
        console.log('AB 2021-01-08:  After checking for this._noProcessing');
    

    It stops on the "if (this._noProcessing(arguments) === false) {" condition. The "console.log('AB 2021-01-08: this._noProcessing is false');" is executed so it never gets onward to push the data to the AJAX method.

    Hope this will give you some ideas on what may be going wrong!

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    Some more information. What is happening is that the field that IS being edited as processing. Around line 5758 (I have added some console.log lines above so it may not correspond 100% with your code)

    Editor.prototype._noProcessing = function (args)
    {
        let processing = false;
    
        $.each(this.s.fields, function(name, field) {
            console.log('Field.  Name: ' + name);
            if (field.processing()) {
                console.log('  Is Processing');
                processing = true;
            }
        });
    

    This shows the field that I have open in the inline-editing as in process. This is what I see in the console:

    Field. Name: jobnum
    Field. Name: vendornumber
    Field. Name: vendorname
    Field. Name: sequence
    Is Processing
    Field. Name: startdate
    Field. Name: enddate

    At this point the "sequence" field is open and I have just clicked on the submit button:

    So it's like it's trying to process it, but then checking if it is processing it and it can't continue because it's being processed.

    Hope this helps!

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    BTW: The "Task #"/"Task Num" is the "sequence" field in the log.

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    I was trying to get the values of the information in the Editor.prototype._submit method I added:

    console.log(JSON.stringify(editFields, null, 4));
    console.log(JSON.stringify(editData, null, 4));
    

    What I found interesting was that the one on editFields fails:

    Uncaught TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    |     property 'jobnum' -> object with constructor 'Editor.Field'
    |     property 's' -> object with constructor 'Object'
    |     ...
    |     property 's' -> object with constructor 'Object'
    --- property 'fields' closes the circle
    at JSON.stringify (<anonymous>)
    at Editor._submit (dataTables.editor.js)
    at dataTables.editor.js
    at Editor._event (dataTables.editor.js)
    at send (dataTables.editor.js)
    at Editor.submit (dataTables.editor.js)
    at Editor.fn (iscm_datatables_test_sql.js)
    at HTMLButtonElement.<anonymous> (dataTables.editor.js)
    at HTMLButtonElement.dispatch (jquery-3.5.1.js:5429)
    at HTMLButtonElement.elemData.handle (jquery-3.5.1.js:5233)
    

    the second one, on editData works. So this **might **indicate that there is something not correct with the fields.

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    One final comment here. After looking at the examples both online and in the zip with the editor, I see that they ALL point the AJAX for BOTH the editor and the table to the same .php script.

    I.e. in simple.html:

    $(document).ready(function() {
        editor = new $.fn.dataTable.Editor( {
            ajax: "../../controllers/staff.php",
    ...
        $('#example').DataTable( {
            dom: "Bfrtip",
            ajax: "../../controllers/staff.php",
    

    In my case, I have to load the table via a different AJAX which pulls data from the web service and then saves it to a SQL table. I'm not sure how the same AJAX script could be used to both handle the editor and load the table. The AJAX script for the table does a fair amount of processing and then returns a JSON string with a "data" structure that matches what's required for the table.

    Could THIS be the source of my problems?

  • allanallan Posts: 61,740Questions: 1Answers: 10,111 Site admin

    Ah hah - yes, if a field is currently "processing" then Editor will not submit until it is finished processing.

    Are you using dependent() anywhere? It sounds like either you aren't returning an object from it or calling its callback function to let Editor know that the processing for the dependent action is complete. At least, that is the most common cause for a field to remain in its processing state.

    Perhaps you can show me your full and unabbreviated Javascript for the DataTable and Editor?

    Allan

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    Nope, not using dependent() in fact this is very plain JS:

        var table;
        var editor;
    
        jQuery(document).ready(function() {
            console.log('DataTable on table: ' + testTableID);
            console.log('Ajax URL: '           + DataAjaxURL);
            console.log('Editor Ajax URL: '    + EditorAjaxURL);
    
            editor = new jQuery.fn.dataTable.Editor(
            {
                table: '#test-table',
                ajax:  {
                    url: EditorAjaxURL
                },
                fields: [
                    {  "label": "Job",        "name": "jobnum"        },
                    {  "label": "Vendor",     "name": "vendornumber"  },
                    {  "label": "Name",       "name": "vendorname"    },
                    {  "label": "Task #",     "name": "sequence"      },
                    {  "label": "Start Date", "name": "startdate"     },
                    {  "label": "End Date",   "name": "enddate"       }
                ]
            });
    
            loadCombinedTable();
    
            // Activate an inline edit on click of a table cell
            jQuery('#test-table').on( 'click', 'tbody td:not(:first-child)', function (e) {
                editor.inline( this, {
                    buttons: { label: 'Save', fn: function () {
                        console.log('submitting data');
                        this.submit();
                    }
                    }
                } );
            } );
    
        });  //  jQuery(document)...
    
    
        function loadCombinedTable() {
    
            var dataForPHP;
            // AB 2021-01-05:  Data for AJAX:  Normally this comes from the page selection and filter options.
            dataForPHP = '[{"rows":[{"jobnumber":"ASG100","job_id":1,"gem_comp_num":900}],"fromdate":"01/03/2021","todate":"01/07/2021","excludedone":true,"inclpriornotdone":true,"exclnonsheculedpos":true}]'
    
            table = jQuery('#test-table').DataTable({
                paging: true,
                pageLength: 10,
                responsive: true,
                retrieve: true,
                "ajax": {
                    "url": DataAjaxURL,
                    "type": "POST",
                    // AB 2021-01-05:  Add parameters to the POST data to PHP.
                    "data": function (d) {
                        return jQuery.extend({}, d, {
                            "action": 0,                  // action_test_datatables
                            "testOption": 2,              // What test option are we using?  2 = 1002 = ISCM_DT_TEST_SCL
                            "dataForPHP": dataForPHP,     // Data to send to PHP.  This would be a JSON list with filter variables.
                        });
                    },
    
    
                    "error": function (xhr, error, code) {
                        //  This is called if there was an error.
                        console.log('AJAX error handler');
                        console.log('XHR:');
                        console.log(xhr);
                        console.log('ERROR:');
                        console.log(error);
                        console.log('CODE:');
                        console.log(code);
                    },
    
    
                    "dataSrc": function (json) {
                        console.log('dataSrc callback');
                        return json.data;      // MUST return json.data!
                    }
                },
    
    
                "drawCallback": function(settings) {
                    console.log('drawCallBack');
                },
    
    
                columns: [
                    {"data": "jobnum",        className: "row-jobnum",         "name": "jobnum"},
                    {"data": "vendornumber",  className: "row-vendornum",      "name": "vendornumber"},
                    {"data": "vendorname",    className: "row-vendorname",     "name": "vendorname"},
                    {"data": "sequence",      className: "row-sequence",       "name": "sequence"},
                    {"data": "startdate",     className: "row-startdate",      "name": "startdate"},
                    {"data": "enddate",       className: "row-enddate",        "name": "enddate"}
                    ]
            });  //  jQuery(#task_po_table)...
            console.log('DataTable set up');
        }
    

    The SQL table I'm using for testing (there are a few more columns in it, but they are not used in the table)

    CREATE TABLE vlt_iscm_quick_combined
    (
        qcomb_sysid             INT(11)        NOT NULL AUTO_INCREMENT COMMENT '',
        jobnum                  VARCHAR(8)     NULL DEFAULT NULL       COMMENT 'Job Number',
        vendornumber            VARCHAR(6)     NULL DEFAULT NULL       COMMENT 'Vendor Number',
        vendorname              VARCHAR(40)    NULL DEFAULT NULL       COMMENT 'Vendor Name',
        sequence                INT            NULL DEFAULT NULL       COMMENT 'Task Sequence',
        startdate               DATE           NULL DEFAULT NULL       COMMENT 'Star Date',
        enddate                 DATE           NULL DEFAULT NULL       COMMENT 'End Date',
        DT_RowId                VARCHAR(36)    NULL DEFAULT NULL       COMMENT 'GUID DataTable Row ID (this may not be needed.  See: https://datatables.net/reference/option/rowId',
        PRIMARY KEY (qcomb_sysid) USING BTREE
    )
    ENGINE = InnoDB
      DEFAULT CHARSET = utf8;
    

    I must be missing something in this, but I cannot see it to save my life! Thanks for all the help!

  • allanallan Posts: 61,740Questions: 1Answers: 10,111 Site admin

    I agree - I don't see anything there that would cause what you are seeing.

    Could you give me a link to your page so I can debug it directly please? Send me a PM by clicking my name above and then "Send message" if you don't want to / can't make the link public.

    Allan

  • arnorbldarnorbld Posts: 110Questions: 20Answers: 1

    Hi Alan,

    Not sure if you got my direct message yesterday, but I set up access for you to our test site yesterday and sent you the information.

  • allanallan Posts: 61,740Questions: 1Answers: 10,111 Site admin

    Thanks for that! I've just replied to your PM, but I'll also post my message here so anyone else who finds this thread will also know what is going on and it might help them resolve what they are seeing:

    Editor thinks the field is in the "processing" state because the processing element is visible. That is happening because the Editor CSS has not be loaded on your page.

    Either add:

    div.DTE_Processing_Indicator {
      display: none;
    }
    

    to your CSS, or load in the Editor CSS (which I would suggest, just to avoid any other issues like this - although I don't think there will be any).

    Regards,
    Allan

This discussion has been closed.