How to wait for processing before new ajax load

How to wait for processing before new ajax load

HPBHPB Posts: 73Questions: 2Answers: 18

Question:
How do I wait for editor to finish it's business before overwriting it's content with an ajax call?

It does seem to wait with a regular reload. For example a refresh of entire page, or clicking a completely different url leaving the page. But I don't know how to get that result when I'm updating a div with an ajax call.

I'm using a partial page with a datatable and editor that I load dynamicly with a $.ajax call based on a user's selection.
The problem arrises when I have an inline form input open and then make a different selection that starts loading the new page into the div element. It tries to submit (and triggering any preceeding events) after the new partial page is loaded.
It works fine when I reload the entire page when the form input is open (and the value has changed), it will then execute the submit before it starts loading.

Current result: After the new partial page (with new datatable and editor) is loaded into the div the initial editor triggers all events that happen onBlur. The initial datatable and data don't exist anymore, so any logic raises errors and I'm unable to correctly submit the changed data.
Desired result: Finish editor event chain before loading new page into div.

I tried making a testcase, but I couldn't figure out (maybe not possible at all) how to use the editor urls used in the examples in a testcase. I will post a simplified use case below.

Steps to reproduce in use case:
- Select a department
- Open inline form input for salary
- Change salary
- Select different department while inline form input is still open

Simplified use case:
A page with a selectlist (id="departmentselect") that triggers function update() on change. An empty div (id="overview") that will hold the partial page loaded with ajax.
update function like this:

            function update() {
                var dept = $('#departmentselect').val();
                $.ajax({
                    url: '<get partial page based on dept>',
                    cache: false,
                    async: false,
                    type: 'GET',
                    datatype: 'json',
                    data: { dept : dept },
                    success: function (data) {
                        $('#overview').html(data);
                    },
                    error: function (jqXHR, textStatus, errorThrown) {
                        alert(errorThrown);
                    }
                });
            }

Partial page loaded with above ajax function:

<table id="overviewtable" class="table">
    <thead>
        <tr>
            <th>Name</th>
            <th>Salary</th>
        </tr>
    </thead>
</table>
<script type="text/javascript">
    //Constants
    var TABLENAME = '#overviewtable';
    $(document).ready(function () {
        var editor = new $.fn.dataTable.Editor({
            ajax: {
                url: '<CRUd-url>',
            },
            table: TABLENAME,
            idSrc: 'empid',
            fields: [
                {
                    label: 'Salary',
                    name: 'Salary',
                },
            ]
        });
        editor.on('preSubmit', function( e, submitdata, action ){
            //Some logic here comparing against other rows
            $(TABLENAME).DataTable().rows().every(function (rowIdx, tableLoop, rowLoop)
            {
                //Errors in use case
                console.log(this.data());               
            });
            return true;
        });
        
        $(TABLENAME).on('click', 'tbody td.editable', function () {
            editor.inline(this, {
                onBlur: 'submit',
                submit: 'allIfChanged'
            });
        });
        
        $(TABLENAME).DataTable({
            ajax: {
                url: '<CRUD-url>',
                type: 'POST',
                data: {
                    action: 'read',
                },
            },
            dom: 'tB',
            buttons: [
                { extend: 'create', editor: editor },
            ],
            retrieve: true,
            stateSave: false,
            pageLength: -1, //All
            initComplete: null,
            rowId: 'empid',
            order: [[0, "asc"]],
            columns: [
                    {
                            data: 'Name',
                    },
                    {
                            data: 'Salary',
                            className: 'editable',
                    },
            ],
            });
    });
</script>

This question has an accepted answers - jump to answer

Answers

  • HPBHPB Posts: 73Questions: 2Answers: 18
    edited March 2017

    I've changed my update function to check if editor and required properties exist and destroying them before loading the new content.
    At least this doesn't give errors, but it does discard the changes. Ideally I would like to process the changed data before loading the new content.

                    if(editor && editor['s'] && editor.s['table'])
                    {
                        var table = editor.s.table;
                        editor.destroy();
                        $(table).DataTable().destroy();
                    }
    
  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin

    What I think you could do is use the display() method to determine if the Editor form is displayed or not in your update() function. If it is, then add an event listener for submitComplete and in that handler call update() again (by which time the form will have finished processing).

    You want to avoid using the properties in the s object of Editor - it is considered to be private and is not documented. The properties can, will and do change between versions.

    Allan

  • HPBHPB Posts: 73Questions: 2Answers: 18

    Thank you for your suggestion.
    There's still a bit of a problem with this solution. It is logic that has to be repeated for every page that loads the partial page, and it gets a little complex when there's fielderrors to be handled and submitSuccess doesn't trigger.

    The suggestion about not using the s object makes sense.
    I've updated the code and now have it placed on the partial page, so I don't have to repeat it and got rid of the s object.
    It now submits the data and ignores the outcome. So if it had field errors it will never submit to server, and if it didn't it will submit to server.
    Snippet:

        var editor; //Global editor variable
        var table; //Global datatable variable
        $(document).ready(function () {
            //Cleanup previous editor
            if(typeof editor !== 'undefined')
            {
                if(editor.display())
                {
                    //These functions have no value anymore as it is not possible to handle success or error at this point
                    //Therefor make them empty functions to avoid errors
                    editor['_submitSuccess'] = function(){};
                    editor['_submitError'] = function(){};
                    editor.submit();
                }
                editor.destroy();
            }
            //Cleanup previous datatable
            if(typeof table !== 'undefined')
                $(table).DataTable().destroy();
    
            //Editor and Datatable initialization here
        });
    

    This feels like a dirty solution, but it works for my use case. Any suggestions about my approach are welcome.

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

    Yeah, its a little bit messy using global variables like that - but I'm not sure that there is really a better way. DataTables has a $.fn.dataTable.isDataTable() static method which could be used instead of the global DataTable variable, but there isn't any such method for Editor.

    Allan

This discussion has been closed.