Potential Editor Bug using "Every"

Potential Editor Bug using "Every"

rf1234rf1234 Posts: 2,939Questions: 87Answers: 415

I tried to implement a button that selects table rows depending on the value of a field in the row. I thought using "every" would be a good option and implemented this code:

//custom button to select all rows that are in the accounting interface using "Every"
$.fn.dataTable.ext.buttons.selectAllInterfaceEvery = {
    text: selectAllInterfaceLabel + '_Every',
    name: "selectedAllInterfaceButton",
    action: function ( e, dt, button, config ) {
        dt.rows({ search: 'applied' }).every( function ( rowIdx, tableLoop, rowLoop ) {
            var data = this.data();
            if ( data.contract_has_infoma.include > 0 ) {
                dt.row(this).select();
            } else {
                dt.row(this).deselect();
            }
        });
    }
};

Surprisingly this solution didn't perform at all. It produced dozens of useless ajax calls and it took over 30 seconds to complete. The final result was correct, but the performance was unsatisfactory:

I ended up implementing this code that performs very well:

//custom button to select all rows that are in the accounting interface
$.fn.dataTable.ext.buttons.selectAllInterface = {
    text: selectAllInterfaceLabel,
    name: "selectedAllInterfaceButton",
    action: function ( e, dt, button, config ) {
        // var sRows = dt.rows({ search: 'applied' });
        var sRows = dt.rows({ search: 'applied' }).data().toArray();
        var interfaceArray = [];
        var notInterfaceArray = [];
        $.each(sRows, function(key, value) {
            if ( value.contract_has_infoma.include > 0 ) {
                interfaceArray.push("#" + value.DT_RowId);
            } else {
                notInterfaceArray.push("#" + value.DT_RowId);
            }
        })
        dt.rows(interfaceArray).select();
        dt.rows(notInterfaceArray).deselect();
    }
};

This wasn't easy either because there is a mistake in the docs.
https://datatables.net/reference/type/row-selector

The "-" should be an "_".

Do you have an explanation why "every" is not performing? Thanks for taking a look!

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 63,179Questions: 1Answers: 10,410 Site admin

    I don't see why the above code would trigger an Ajax call at all since there is no ajax functionality in the above? Or have I missed it?

    Good to hear you've got it working now though.

    Allan

  • rf1234rf1234 Posts: 2,939Questions: 87Answers: 415

    Exactly, Allan! It does not trigger an Ajax Call. But does the functionality behind "every" trigger such a call? For me this behavior was very surprising and I don't understand it either.

    This is the entire javascript code including the two buttons. Can you find anything there that would explain this weird behavior?

    var infomaExcludeEditor = new $.fn.dataTable.Editor( {
        ajax: {
            url: 'actions.php?action=tblInfomaContractData',
        },
        table: "#tblInfomaContractData",
        fields: [ {
                name:      "contract_has_infoma.include",
                type:      "checkbox",
                separator: "|",
                options:   [
                    { label: '', value: 1 }
                ]
            }
        ]        
    } );
    
    var infomaContractTable = $('#tblInfomaContractData').DataTable( {
        dom: "Bfrltip",
        ajax: {
            url: 'actions.php?action=tblInfomaContractData'
        },
        pageLength: 50,
        lengthMenu: [5, 10, 20, 50, 100, 200, 500, 1000],
        columns: [
            {   data: "contract_has_infoma.include",
                render: function ( data, type, row ) {
                    if ( type === 'display' ) {
                        return '<input type="checkbox" class="editor-include">';
                    }
                    return data;
                }
            },
            {   data: "contract_has_infoma.interface_status",
                render: function ( data, type, row ) {
                    if ( data <= 0 ) {
                        return 'unbearbeitet';
                    } else if ( data <= 1 ) {
                        return 'unvollständig';
                    } else if ( data <= 2 ) {
                        return 'vollständig und validiert';
                    }
                }
            },
            {   data: "creditor.name",
                render: function ( data, type, row ) {
                    return renderCounterparty(row.contract, row.creditor,
                                              row.gov_manual_creditor     );
                }
            },
            {   data: "govdept.name" },
            {   data: "govdept.acct_system",
                render: function ( data, type, row ) {
                    return renderAcctSystemContract(data, row.govdept.muni_number, 
                                                  row.govdept.acct_system_provider);
                }
            },
            {   data: "gov.regional_12" },
            {   data: "contract.instrument",
                render: function ( data, type, row ) {
                    return renderInstrument(row.contract.instrument);
                }
            },
            {   data: "contract.type",
                render: function ( data, type, row ) {
                    return renderTypeDerivative(data, row.contract.derivative);
                }
            },
            {   data: "contract.start_date"},
            {   data: "contract.number"},
            {   data: "contract.serial"},
            {   data: "contract.purpose",
                render: function ( data, type, row ) {
                    return renderPurpose(row.contract.serial, row.contract.purpose,
                                         row.contract.label);
                }
            },        
            {   data: "contract.update_time" }
        ],        
        columnDefs: [
            // targets may be classes
            {   targets: "hiddenCols", visible: false },
            {   targets: "cnt", className: "text-center"}
        ],
        // sequence: update time desc, 
        order: [ [ 3, 'asc' ], [1, 'asc'] ],
        select: {
            style: 'os',
            selector: 'td:not(:first-child)' // no row selection on first column
        },    
        buttons: [        
                    {extend: "editInfomaSettings", editor: infomaContractEditor}, 
                        "selectAll",
                        "selectAllInterface",
                        "selectAllInterfaceEvery",
                        "selectNone",
    //                    "migrateContractHasInfoma", 
                        "selectedInterfaceTrue",
                        "selectedInterfaceFalse", 
                        "colvis"
        ],
        rowCallback: function ( row, data ) {
            // Set the checked state of the checkbox in the table
            $('input.editor-include', row).prop( 'checked', data.contract_has_infoma.include == 1 );
           //to be edited records have font thick
            if ( data.contract_has_infoma.interface_status < 1 ) {
                $(row).addClass('fontThick');
            } else {
                $(row).removeClass('fontThick');
            }
        }    
    } );
    
    infomaContractTable 
        .on('init', function () {
            $('#content').fadeIn('fast');        
            $.busyLoadFull("hide", { 
              // options here 
            });
    //        if ( currentUserId == 64 ) {
    //            infomaContractTable.buttons('migrateContractHasInfomaButton:name').nodes().removeClass('hidden');     
    //        }
            infomaContractTable.columns.adjust()
                               .responsive.recalc();
            var data = infomaContractTable.rows().data().toArray();
            var contractIdArray = [];
            $.each(data, function(key, value) {
                contractIdArray.push(value.contract.id);
            })
            if ( contractIdArray.length > 0 ) {
                $.ajax({
                    type: "POST",
                    url: 'actions.php?action=processContractHasInfoma',
                    data: {
                        contractIdArray: JSON.stringify(contractIdArray),
                        insertOnly: 0 //we also need to update existing status!!
                    },
                    success: function () {
                        ajaxReloadTbls( [infomaContractTable] );
                    }
                });
            }
        })
        .on( 'search', function () {
            var selected = infomaContractTable.rows({ selected: true });
            if ( selected.any() ) {
                selected.deselect();
            }
        } )
        .on ( 'select', function (e, dt, type, indexes) {
            var selected = dt.rows({ selected: true });
            if ( selected.any() ) {
                dt.buttons('infomaContractButton:name').nodes().removeClass('hidden');            
            }
            acctSystems = [];
            acctSystemProviders = [];
            dt.rows({ selected: true }).every( function ( rowIdx, tableLoop, rowLoop ) {
                var data = this.data();
                if ( acctSystems.indexOf(data.govdept.acct_system) < 0 ) {
                    acctSystems.push(data.govdept.acct_system);
                }
                if ( acctSystemProviders.indexOf(data.govdept.acct_system_provider) < 0 ) {
                    acctSystemProviders.push(data.govdept.acct_system_provider);
                }
            });
         })     
        .on( 'deselect', function( e, dt, type, indexes ) {
            var selected = dt.row({ selected: true });
            if ( ! selected.any() ) {
                dt.buttons('infomaContractButton:name').nodes().addClass('hidden');
            } else { //some records are still selected ==> we need to check again!
                acctSystems = [];
                acctSystemProviders = [];
                dt.rows({ selected: true }).every( function ( rowIdx, tableLoop, rowLoop ) {
                    var data = this.data();
                    if ( acctSystems.indexOf(data.govdept.acct_system) < 0 ) {
                        acctSystems.push(data.govdept.acct_system);
                    }
                    if ( acctSystemProviders.indexOf(data.govdept.acct_system_provider) < 0 ) {
                        acctSystemProviders.push(data.govdept.acct_system_provider);
                    }
                });
            }
            ajaxReloadTbls( [dt] );
    });
    
    $('#tblInfomaContractData').on( 'change', 'input.editor-include', function () {
        //if the value is changed to "include" values need to be edited and the modal opens
        if ( $(this).prop( 'checked' ) == 1) {
    //        var acct = infomaContractTable.cell($(this).closest('tr'), ".acctSolution").data();
    //        setEditorAcctMaintenanceDependencies(infomaContractEditor, [acct], acct);
            //the on.open event should work! see tblContractAccInterfaceEditor.js
            infomaContractEditor
                .edit( $(this).closest('tr') )
                .set( 'contract_has_infoma.include', 1 )
                .title($.fn.dataTable.Editor.defaults.i18n.edit.title)
                .buttons({
                    label: $.fn.dataTable.Editor.defaults.i18n.edit.submit,
                    className: 'btn-showall-color',
                    fn: function () {
                        this.submit();
                    }
                });
            ajaxReloadTbls( [infomaContractTable] );            
        } else {  //if you just exclude a record nothing needs to be edited
            infomaExcludeEditor
                .edit( $(this).closest('tr'), false )
                .set( 'contract_has_infoma.include', 0 )
                .submit();
        }
        
    } );
    
  • rf1234rf1234 Posts: 2,939Questions: 87Answers: 415

    Found the reason: on every deselect I do an ajax reload of the data table. And that happens many times when using the above logic with "Every". It only happens once when using the array based solution that I implemented!

  • kthorngrenkthorngren Posts: 21,154Questions: 26Answers: 4,919
    Answer ✓

    Looks like you are building an array in the each solution then after the loop you are doing one select and one deselect. Where in the every loop you are individually selecting or deselecting rows. If you were to build an array like the each solution then you would have only one ajax call.

    Kevin

  • rf1234rf1234 Posts: 2,939Questions: 87Answers: 415
    edited August 2019

    Amazing! same thought at the same time, Kevin!

    This is where I do the ajax call after every deselect:

    No bug! But the array based solution is certainly the best in this case because I can't get rid of the ajax reload after deselecting a row.

This discussion has been closed.