Performance Issues with dynamic content loading

Performance Issues with dynamic content loading

rf1234rf1234 Posts: 2,990Questions: 87Answers: 421
edited August 2022 in Editor

I have a question - answer dialogue that loads follow on questions depending on user responses. This works very well. There is only one issue: After about a dozen questions and answers it becomes slow. Seems like the browser is getting "congested" with that stuff.

Note:
ctrPSCEditor is the parent Editor, while vatQaEditor is the Editor of field type "datatable". The completed Q&As are displayed in field type "datatable". Based on user replies new questions or the final result are loaded via ajax from my content management system.

Is there anything I can do to fix this?

This is my relevant code:

vatQaEditor //child Editor in field type "datatable"
    .on('open', function ( e, mode, action ) {
        //read following question and set the editor fields
            $.ajax({
                type: "POST",
                url: 'actions.php?action=getQaEditorValues',
                data: {
                    ctrId: parentId,
                    vatAssessmentType:  vatAssessmentType,
                    vatSubcategoryId: ctrPSCEditor.val("vat_result.vat_subcategory_id"),
                },
                dataType: "json",
                success: function (d) {
                    if ( d.vat_question === "no question found" ) {
                        if ( ctrPSCEditor.field("vat_qa[].id").dt().rows().count() <= 0 ) {
                            vatQaEditor.close();
                            return;
                        }
                    }
                    //if there are options this means we have following questions and
                    //not a result yet!!
                    if ( d.vat_options_arr.length ) {
                        vatQaEditor.set({'vat_qua.vat_option_alias': ''})
                                   .show('vat_qa.vat_option'); 
                        ctrPSCEditor.set( { 'vat_result.vat_result': "",
                                            'vat_result.vat_hint': "" } );
                        $( ctrPSCEditor.field('vat_qa[].id').node() ).change();
                        vatQaEditor.field('vat_qa.vat_option').update(d.vat_options_arr);
                        vatQaEditor
                            .title(lang === 'de' ? 'PSC USt.-Frage ' + d.vat_number + ' beantworten' : 
                                           'Answer PSC VAT question ' + d.vat_number)
                            .set( { 'vat_qa.vat_question':  d.vat_question,
                                    'vat_qa.vat_hint':      d.vat_hint,
                                    'vat_qa.vat_number':    d.vat_number } );
                    } else { //we have a result already: hence we fill the result table
                        vatQaEditor.set({'vat_qua.vat_option_alias': 'no option'})
                                   .hide('vat_qa.vat_option');
                        ctrPSCEditor.set( { 'vat_result.vat_result': d.vat_question,
                                            'vat_result.vat_hint': d.vat_hint } );
                        $( ctrPSCEditor.field('vat_qa[].id').node() ).change();
                        vatQaEditor.close();
                    }
                    //make sure all changes are saved!!
                    $.ajax({
                        type: "POST",
                        url: 'actions.php?action=updateVatResult',
                        data: {
                            ctrId: parentId,
                            vatAssessmentType:  vatAssessmentType,
                            vatSubcategoryId: ctrPSCEditor.val("vat_result.vat_subcategory_id"),
                            vatResult: ctrPSCEditor.val('vat_result.vat_result'),
                            vatHint: ctrPSCEditor.val('vat_result.vat_hint')
                        },
                        dataType: "json",
                        success: function (data) {
                            if ( data === "reload" ) {
                                ctrPSCTable.ajax.reload();
                            }
                        }
                    });
                }
            });
    })

and the field type "datatable" Editor's initialization code:

var vatQaEditor = new $.fn.dataTable.Editor({
    ajax: {
        url: 'actions.php?action=tblVatQa',
        data: function ( d ) {
            d.ctr_id = parentId;
            // 0: "vat", 1: "preTax" or 2: "preTaxCorrection"
            d.vatAssessmentType = vatAssessmentType;
        }
    },
    formOptions: { main: { focus: null } },
    fields: [ {
            label: lang === 'de' ? 'Frage:' : 'Question:',
            name: "vat_qa.vat_question",
            type: "quill",
            toolbar: false,
            opts: {
                readOnly: true
            }
        }, {
            label: lang === 'de' ? 'Hinweis:' : 'Hint:',
            name: "vat_qa.vat_hint",
            type: "quill",
            toolbar: false,
            opts: {
                readOnly: true
            }
        }, {
            label: lang === 'de' ? 'Antwort:' : 'Reply:',
            name: "vat_qa.vat_option",
            type: "select",
            placeholder: lang === 'de' ? 'Bitte Option wählen' : 'Please select option',
        }, {
            type: "hidden",
            name: "vat_qa.id"
        }, {
            type: "hidden",
            name: "vat_qa.ctr_id"
        }, {
            type: "hidden",
            name: "vat_qa.vat_number"
        }, {
            type: "hidden",
            name: "vat_qua.vat_option_alias"
        }
    ],
    buttons: ( [
        {
            label: lang === 'de' ? 'Schließen' : 'Close',
            action: function () {
                this.close();
            }
        },
        {
            label: $.fn.dataTable.Editor.defaults.i18n.create.submit,
            className: 'btn-showall-color',
            fn: function () {
                this.submit();
            }
        }
    ] )
});

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    There is nothing really obvious there unfortunately. What you describe is normally due to events being added again and again, but I don't see that in the above code (unless I'm missing it).

    Can you link to a page showing that so I can take a look?

    Allan

  • rf1234rf1234 Posts: 2,990Questions: 87Answers: 421

    Hi Allan,
    pretty hard for you to reproduce the issue because you would need to respond to about 25 legal questions in German, always give the right answer to make the dialogue continue and then somehow locate the problem ...

    I have tried a number of things using flags to avoid field updates and triggering event handlers etc. I also checked it in the debugger. It all worked and those calls were avoided wherever possible but it hasn't helped.

    What I found is that the "create" statement below became slower and slower in the debugger the more questions were shown to the user.

    This is what caused the problem

    vatQaEditor
        .on( 'submitSuccess', function( e, json, data, action ) { 
            if ( typeof json.data[0] !== 'undefined' ) {
                vatQaEditor
                    .create({nest: true});
            }
        })
    
  • rf1234rf1234 Posts: 2,990Questions: 87Answers: 421
    edited August 2022

    Hi Allan,

    no that wasn't what caused the problem ...

    I found out that when I programmatically close the child Editor (field type "datatable") the "opened" event of the parent Editor gets triggered. All of that code that has many event handlers got executed over and over again for about 25 times and that caused the problem.

    The sequence was:
    - "create" child Editor (programmaticaly or manually opened)
    - user answers question and submits
    - "close" child Editor (programmatically closed with "this.submit()")
    - "opened" event in parent Editor
    - "create" child Editor (programmatically opened)
    - and so on and so forth

    I solved it by using flags (see below).
    I am not sure whether this is a bug. It is a bit surprising though. Since I need the code to also run after the last user question has been answered I am tempted to not call it a bug. Amazing that only the "opened" event gets triggered in this case NOT the "open" event of the parent Editor.

    ctrPSCEditor
        .on('opened', function ( e, mode, action ) { //event handler is somewhat slower
            if ( ! firstRun ) {
                firstRun = true;
                return;
            }
            var self = this; 
            setTimeout(function(){            
                $( [ self.field('vat_result.vat_subcategory_id').node(),
                     self.field('vat_qa[].id').node() ] ).change( function() {
                    if ( self.field("vat_qa[].id").dt().rows().count() > 0 ) {
                        self.field("vat_result.vat_subcategory_id").disable();
                    } else {
                        self.field("vat_result.vat_subcategory_id").enable();
                    }
                });
                $( self.field('vat_qa[].id').node() ).change();
                //trigger the change again!! after a short period of time
                setTimeout(function() {
                    $( self.field('vat_qa[].id').node() ).change();
                },700);
                if ( vatAssessmentType == 0 ) {
                    $( [ self.field('ctr.VAT_decision').node(),
                         self.field('vat_qa[].id').node() ] ).change( function() {
                        if (self.val('ctr.VAT_decision') == '1') {
                            self.show( ['ctr.VAT_charged', 'ctr.VAT_comment'] );
                        } else {
                            self.set( { 'ctr.VAT_charged': 0, 'ctr.VAT_rate': 0,
                                        'ctr.VAT_mixed_rate': '' } )
                            self.hide(['ctr.VAT_start_date', 'ctr.VAT_comment',
                                       'ctr.VAT_charged', 'ctr.VAT_rate',
                                       'ctr.VAT_mixed_rate', 'ctr.input_tax_deductible',
                                       'ctr.input_tax_rate', 'ctr.input_tax_mixed_rate']);
                        }
                    });
                    $( self.field('ctr.VAT_decision').node() ).change();
                } else if ( vatAssessmentType == 1 ) {
                    $( [ self.field('ctr.input_tax_decision').node(),
                         self.field('vat_qa[].id').node() ] ).change( function() {
                        if (self.val('ctr.input_tax_decision') == '1') {
                            self.show( ['ctr.input_tax_deductible', 'ctr.VAT_comment'] );
                        } else {
                            self.set( { 'ctr.input_tax_deductible': 0, 'ctr.input_tax_rate': 0,
                                        'ctr.input_tax_mixed_rate': '' } )
                            self.hide(['ctr.VAT_start_date', 'ctr.VAT_comment',
                                       'ctr.VAT_charged', 'ctr.VAT_rate',
                                       'ctr.VAT_mixed_rate', 'ctr.input_tax_deductible',
                                       'ctr.input_tax_rate', 'ctr.input_tax_mixed_rate']);
                        }
                    });
                    $( self.field('ctr.input_tax_decision').node() ).change();
                } else {
                    $( [ self.field('ctr.input_tax_correction_decision').node(),
                         self.field('vat_qa[].id').node() ] ).change( function() {
                        if (self.val('ctr.input_tax_correction_decision') == '1') {
                            self.show( ['ctr.VAT_comment'] );
                        } else {
                            self.hide(['ctr.VAT_start_date', 'ctr.VAT_comment',
                                       'ctr.VAT_charged', 'ctr.VAT_rate',
                                       'ctr.VAT_mixed_rate', 'ctr.input_tax_deductible',
                                       'ctr.input_tax_rate', 'ctr.input_tax_mixed_rate']);
                        }
                    });
                    $( self.field('ctr.input_tax_correction_decision').node() ).change();
                }
                if ( vatAssessmentType == 0 ) {
                    
                    $( [ self.field('ctr.VAT_charged').node(),
                         self.field('vat_qa[].id').node() ] ).change( function() {
                        if (self.val('ctr.VAT_charged') == '1') {
                            self.show( ['ctr.VAT_start_date', 'ctr.VAT_rate'] );
                        } else {
                            self.set( { 'ctr.VAT_rate': 0 } )
                                .hide( ['ctr.VAT_start_date', 'ctr.VAT_rate'] );
                        }
                    });
                    $( self.field('ctr.VAT_charged').node() ).change();
    
                    $( [ self.field('ctr.VAT_rate').node(),
                         self.field('vat_qa[].id').node() ] ).change( function() {
                        if (self.val('ctr.VAT_rate') == '3') {
                            self.show( ['ctr.VAT_mixed_rate'] );
                        } else {
                            self.set( { 'ctr.VAT_mixed_rate': '' } )
                                .hide( ['ctr.VAT_mixed_rate'] );
                        }
                    });
                    $( self.field('ctr.VAT_rate').node() ).change();
                    
                } else if ( vatAssessmentType == 1 ) {   
                    
                    $( [ self.field('ctr.input_tax_deductible').node(),
                         self.field('vat_qa[].id').node() ] ).change( function() {
                        if (self.val('ctr.input_tax_deductible') == '1') {
                            self.show( ['ctr.VAT_start_date', 'ctr.input_tax_rate'] );
                        } else {
                            self.set( { 'ctr.input_tax_rate': 0 } )
                                .hide( ['ctr.VAT_start_date', 'ctr.input_tax_rate'] );
                        }
                    });
                    $( self.field('ctr.input_tax_deductible').node() ).change();
    
                    $( [ self.field('ctr.input_tax_rate').node(),
                         self.field('vat_qa[].id').node() ] ).change( function() {
                        if (self.val('ctr.input_tax_rate') == '3') {
                            self.show( ['ctr.input_tax_mixed_rate'] );
                        } else {
                            self.set( { 'ctr.input_tax_mixed_rate': '' } )
                                .hide( ['ctr.input_tax_mixed_rate'] );
                        }
                    })
                    $( self.field('ctr.input_tax_rate').node() ).change();
                }
            }, 300);
        })
    
  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin
    Answer ✓

    Ah! That will do it - the event bubbles. Yes, that is intentional. Like DOM events, a number of the Editor events bubble up through the document so you can do things like adding an event listener on the document as a catch all.

    I can see how that could be annoying in cases. You could add an event listener on the inner Editor and stopPropagation, on the event. I'm also going to check what context the event is executed in, then something like:

    if (this !== editor1) {
      return;
    }
    

    would work. Good to hear you have a workaround now though.

    Allan

  • rf1234rf1234 Posts: 2,990Questions: 87Answers: 421

    Hi Allan,

    tried this:

    ctrPSCEditor
        .on('opened', function ( e, mode, action ) { 
            if ( this !== ctrPSCEditor ) {
                return;
            }
    //        if ( ! firstRun ) {
    //            firstRun = true;
    //            return;
    //        }
        });
    

    ctrPSCEditor being the parent Editor.

    It did not work! So I'll stick to my workaround for the time being.

Sign In or Register to comment.