jQuery sortColumns plugin: How to sort correctly with rowspan

后端 未结 2 810
北海茫月
北海茫月 2021-02-06 09:18

Following this post jQuery table sort (github link: https://github.com/padolsey/jQuery-Plugins/blob/master/sortElements/jquery.sortElements.js), I am successfully sort columns,

相关标签:
2条回答
  • 2021-02-06 09:35

    Conditions for the code to work:

    • Columns containing tds with rowspan must all be on the left of the table
    • All the tds in these columns must have a rowspan, even if it's 1
    • The groups of rows to sort are made with the rightmost of these columns (but it can easily be changed)

    jsFiddle: http://jsfiddle.net/5GrAC/77/

    var inverse = false;
    
    function sortColumn(index) {
        var trs = $('#resultsTable > tbody > tr'),
            nbRowspans = trs.first().children('[rowspan]').length,
            offset = trs.first().children('[rowspan]').last().offset().left;
    
        var tds = trs.children('[rowspan]').each(function() {
            $(this).data('row', $(this).parent().index());
            $(this).data('column', $(this).index());
            $(this).data('offset', $(this).offset().left)
        }).each(function() {
            if($(this).data('offset') != offset)
                return;
    
            var rowMin = $(this).data('row'),
                rowMax = rowMin + parseInt($(this).attr('rowspan'));
    
            trs.slice(rowMin, rowMax).children().filter(function() {
                return $(this).index() == index + $(this).parent().children('[rowspan]').length - nbRowspans;
            }).sortElements(function(a, b) {
                a = convertToNum($(a).text());
                b = convertToNum($(b).text());
    
                return (
                    isNaN(a) || isNaN(b) ?
                    a > b : +a > +b
                    ) ?
                inverse ? -1 : 1 :
                inverse ? 1 : -1;
            }, function() {
                return this.parentNode;
            });
        });
    
        var trs = $('#resultsTable > tbody > tr');
        tds.each(function() {
            if($(this).parent().index() != $(this).data('row'))
                $(this).insertBefore(trs.eq($(this).data('row')).children().eq($(this).data('column')));
        });
    
        inverse = !inverse;
    }
    

    Quick explanations:

    • Finding all tds with rowspan
    • Positions of these tds are saved, including left offset
    • These tds are filtered by their original offset to work only with the rightmost ones
    • trs related to each kept td are sorted using the wanted column
    • All tds with rowspan are finally moved back to their original position if necessary

    About question 2, I will only complete bartlaarhoven's answer by saying, the code can also be written like the following:

    return (
            (isNaN(a) || isNaN(b) ? a > b : +a > +b) ? 1 : -1
        ) * (inverse ? -1 : 1);
    

    You can easily read that inverse is used to inverse the result.

    0 讨论(0)
  • 2021-02-06 09:48

    Considering question 1, try this code:

    var inverse = false;
    var curRowSpan = 0;
    var curIndex = 0;
    var doRowSpan = false;
    function sortColumn(index){
        index = index + 1;
        var table = jQuery('#resultsTable');
        table.find('td').filter(function() {
            var result = false;
            // if it is a column before the sorting column, watch the rowSpan
            if (curRowSpan == 0 && jQuery(this).index() < index && jQuery(this).attr("rowspan") > 1) {
                curRowSpan = jQuery(this).attr("rowspan");
                doRowSpan = true;
                // we are not in the sorting column so we can safely continue
                continue;
            }
    
            if(!doRowSpan) curIndex = index - (curRowSpan?1:0);
            else curIndex = index;
    
            if(jQuery(this).index() == curIndex) {
                // we are at the sorting column
                if(curRowSpan > 0) {
                    curRowSpan--;
                }
                // set this to false for the following row
                doRowSpan = false;
                result = true;
            }
    
            return result;
        }).sortElements(function(a, b){
            a = convertToNum($(a).text());
            b = convertToNum($(b).text());
    
            return (
                isNaN(a) || isNaN(b) ?
                a > b : +a > +b
            ) ?
                inverse ? -1 : 1 :
                inverse ? 1 : -1;
            },function(){
                return this.parentNode;
            });
            inverse = !inverse;
        }
        function convertToNum(str){
            if(isNaN(str)){
                var holder = "";
                for(i=0; i<str.length; i++){                                
                    if(!isNaN(str.charAt(i))){
                        holder += str.charAt(i);
                    }
                }
                return holder;
            }else{
                return str;
            }
        }
    

    Considering question 2; let's deduct where it comes from. First of all we would like to check whether a > b, and, as you already saw correctly, we make a difference between string comparison and number comparison.

    We would then simply give:

    return (
            isNaN(a) || isNaN(b) ?
            a > b : +a > +b
            ) ? 1 : -1;
    

    This checks whether a > b (either string-wise or number-wise) and then returns 1 on true and -1 on false.

    Now we insert the inverse parameter, which should inverse the result. This means that if inverse == true, then 1 becomes -1 and -1 becomes 1. In code, this bold piece of text would replace each occurrence of 1 with inverse ? -1 : 1 and each occurrence of -1 with inverse ? 1 : -1. Which is exactly what is done in the resulting code.

    UPDATE: Added doRowSpan in the code because it should not adapt the index if we are in the <tr> that contains the rowspan-td.

    0 讨论(0)
提交回复
热议问题