Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery table sorter not working for values that are fetched by AJAX

I have implemented jQuery tablesorter in my project.

My table consist of input textfields of which some are populated by ajax. Table sorting is working perfectly for the input fields that are entered by user, but the input fields that are populated from database using ajax are not sorting properly.

My code :

jQuery(function () {
    jQuery('#tablesorter-demo').tablesorter({
        widgets: ['zebra', 'stickyHeaders'],
        headers: {
            2: {
                sorter: 'inputs'
            },
            3: {
                sorter: 'inputs'
            },
            5: {
                sorter: 'inputs'
            }
        }
    });
});

jQuery.tablesorter.addParser({
    id: 'inputs',
    is: function (s) {
        return false;
    },
    format: function (s, table, cell, cellIndex) {
        var jQueryc = jQuery(cell);

        // return 1 for true, 2 for false, so true sorts before false
        if (!jQueryc.hasClass('updateInput')) {
            jQueryc
                .addClass('updateInput')
                .bind('keyup', function () {
                    console.log(table);
                    jQuery(table).trigger('updateCell', [cell, false]); // false to prevent resort
                });
        }
        return jQueryc.find('input[type="text"]').val();
    },
    type: 'text'
});

My AJAX function :

jQuery('.bulkupload').keyup(function () {
    check = 1;
    jQuery("#" + jQuery(this).attr("id")).css("color", "#928F8F");
    var part_no1 = jQuery("#" + jQuery(this).attr("id")).val();
    var fieldcount = part_no1.toString().length;
    var thenum = jQuery(this).attr("id").replace(/^\D+/g, '');

    if (jQuery('#qty' + thenum).val() == '') {
        jQuery('#qty' + thenum).val('Enter Quantity');
        jQuery('#qty' + thenum).css("color", "#DF1F26");
    }

    var url1 = "<?php echo Mage::getBaseUrl(); ?>availableorders/index/getdetails";
    jQuery.ajax({
        type: "POST",
        url: url1,
        data: {
            part_no1: part_no1
        },
        success: function (response) {
            if (response == "check") {
                jQuery('#item_name' + thenum).val("Not Found");
                jQuery('#item_desc' + thenum).val("Not Found");
                jQuery('#av_qty' + thenum).css("color", "#DF1F26");
                jQuery('#item_name' + thenum).css("color", "#DF1F26");
                jQuery('#item_desc' + thenum).css("color", "#DF1F26");
                jQuery('#brand_name' + thenum).css("color", "#DF1F26");
            } 
            else {
                var result1 = jQuery.parseJSON(response);

                jQuery('#item_name' + thenum).val(result1.prodname1);
                jQuery('#item_desc' + thenum).val(result1.productdescription1);
                jQuery('#brand_name' + thenum).val(result1.brand);
                jQuery('#av_qty' + thenum).css("color", "#DF1F26");
                jQuery('#item_name' + thenum).css("color", "#DF1F26");
                jQuery('#item_desc' + thenum).css("color", "#DF1F26");
                jQuery('#brand_name' + thenum).css("color", "#DF1F26");
                if (jQuery('#av_qty' + thenum).val(result1.stock) == 0) {
                    jQuery('#av_qty' + thenum).val("Not in Stock");
                } else {
                    jQuery('#av_qty' + thenum).val(result1.stock);
                }

                jQuery("#tablesorter-demo").trigger('updateCell');
            }
        }
    });
});
like image 724
magento_practitioner Avatar asked Nov 01 '22 20:11

magento_practitioner


1 Answers

From the options & widgets that you are using, it appears that you are actually using my fork of tablesorter instead of the original plugin.

Anyway, the widget you created for the input parser is binding to the cell

jQuery(cell).bind('keyup', function () { ... }

but when the table is sorted, the cells are removed from the tbody causing any event bindings to break. The way to get around this problem is to use delegated event binding on the tbody (but done outside of the widget format function because it only needs to be done once).

jQuery('table tbody').on('keyup', 'input', function(e) {
    var $input = $(e.target);
    ...
}

Additionally, when you update a lot of inputs from your ajax call, it would be better to just update them all at once (.trigger('update')), otherwise you're using the updateCell method too much and likely causing the entire process to take longer than necessary.

This demo uses a very similar method to update checkboxes within a table, so it should be fairly straight-forward to convert it to make it work with input values - if you have trouble, just post here and I'll help.

// checkbox parser
$.tablesorter.addParser( {
    id: 'checkbox',
    is: function( s ) {
        return false;
    },
    format: function( s, table, cell ) {
        var $c = $( cell ).find( 'input' );
        return $c.length ? $c.is( ':checked' ) ? 1 : 2 : s;
    },
    type: 'numeric'
});

$( function() {
    // using .on() which requires jQuery 1.7+
    $( 'table' ).on( 'tablesorter-initialized', function() {

        // class name to add on tr when checkbox is checked
        var highlightClass = 'checked',
        // resort the table after the checkbox is modified?
        resort = true,
        // if a server side database needs to be updated, do it here
        serverCallback = function( table, inputElement ) {},

        $table = $( this ),
        c = this.config,
        wo = c && c.widgetOptions,
        // include sticky header checkbox; if installed
        $sticky = c && wo.$sticky || '',
        doChecky = function( c, col ) {
            $table
                .children( 'tbody' )
                .children( 'tr:visible' )
                .children( 'td:nth-child( ' + ( parseInt( col, 10 ) + 1 ) + ' )' )
                .find( 'input' )
                .each( function() {
                    this.checked = c;
                    $( this ).trigger( 'change' );
                });
        };

        $table
            .children( 'tbody' )
            .on( 'change', 'input', function() {
                // ignore change if updating all rows
                if ( $table[0].ignoreChange ) { return; }
                var col, $this = $( this );
                $this.closest( 'tr' ).toggleClass( highlightClass, this.checked );
                $this.trigger( 'updateCell', [ $this.closest( 'td' ), resort ] );
                // if your server side database needs more parameters, add them here sent to the callback
                serverCallback( $table[0], this );
                // uncheck header if any checkboxes are unchecked
                if ( !this.checked ) {
                    $table.add( $sticky ).find( 'thead input' ).prop( 'checked', false );
                }
            })
            .end()
            .add( $sticky )
            .find( 'thead input' )
            // Click on checkbox in table header to toggle all inputs
            .on( 'change', function() {
                // prevent updateCell for every cell
                $table[0].ignoreChange = true;
                var c = this.checked,
                    col = $( this ).closest( 'th' ).attr( 'data-column' );
                doChecky( c, col );
                // update main & sticky header
                $table.add( $sticky ).find( 'th[data-column=' + col + '] input' ).prop( 'checked', c );
                $table.children( 'tbody' ).children( 'tr:visible' ).toggleClass( highlightClass, c );
                // update all at once
                $table[0].ignoreChange = false;
                $table.trigger( 'update', [ resort ] );
            })
            .on( 'mouseup', function() {
                return false;
            });

    });
});

I should also note that when your ajax call is done and the changes have been applied, that is when an "update" method should be triggered, not "updateCell".

Lastly, there is an existing input-select parser but it doesn't include a method to prevent massive updateCell method calls versus updating the table all at once.

like image 70
Mottie Avatar answered Nov 09 '22 12:11

Mottie