DevTN
DevTN

Reputation: 593

how to sort a table with child rows based on a column in the parent rows in jQuery

I have a HTML table which includes parents and child rows controlled by data-target. I can collapse and expand my rows.

I want to sort my table based on Total Grand column descending. The sort should be only on parents rows <tr> with class .accountLevelLine

My solution is almost working but still some issues. It's sorting the parents rows but the child rows are not aligned together with the parents therefore when expand/collapse the child rows they don't belong to the right parents rows.

Any idea please what am I doing wrong ? I tried multiple solutions on different threads here but the child rows are still causing an issue. Thank you for your support.

Here is my code :

$(document).ready(function() {
// This section for Collapse/Expand feature to hide/unhide child rows
    $('#pool').on('click', 'tbody > tr > .collapsed', function() {
        const collapsed = $(this);
        const accountName = $(this).siblings('.AccountName').text().replace(/[^a-z0-9]/gi, '');
        const trItem = $(this).parents('tr').siblings('.id' + accountName);
        
        trItem.each(function() {
            if($(this).hasClass("hidden")) {
                collapsed.text('▼');
                $(this).removeClass('hidden');
            } else {
                collapsed.text('►');
                $(this).addClass('hidden');
            }
        });
    });
    
// !!!!!!the issue starts here
// This section is for sorting the parents row based on Grand Total column from highest to lowest

 // get rows as array and detach them from the table
var rows = $('#pool tr.accountLevelLine:not(:first)').detach();
// sort the parents rows by number in the td with class "GrandTotal"
rows.sort(function (row1, row2) { 
return parseInt($(row1).find('td.GrandTotal').text()) - parseInt($(row2).find('td.GrandTotal').text());
}); 
// add each row back to the table in the sorted order
rows.each(function () { 
$(this).appendTo('#pool');
});

    
});
    table, th, td {
        border: 1px solid;
    }

    .collapsed {
        cursor: pointer;
    }

    .hidden {
        display:none;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="nowrap table table-hover table-bordered" id="pool">
<thead>
<tr class="collapsed">
<th></th>
<th>Account Name</th><th>0</th><th>5</th><th>25</th><th>50</th><th>80</th><th>Grand Total</th>   </tr>
</thead>
<tbody>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAccountantGeneral">►</td>
<td class="AccountName">Accountant General</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">1300000</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1300000</td>
</tr>
<tr class="pool-items collapse hidden idAccountantGeneral">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000733349</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">1300000</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1300000</td>
</tr>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAenaSmeSa">►</td>
<td class="AccountName">Aena S.m.e. Sa.</td>
<td class="0"></td>
<td class="5">6059994</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">6059994</td>
</tr>
<tr class="pool-items collapse hidden idAenaSmeSa">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000759948</td>
<td class="0"></td>
<td class="5">1009999</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1009999</td>
</tr>
<tr class="pool-items collapse hidden idAenaSmeSa">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000897454</td>
<td class="0"></td>
<td class="5">5049995</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">5049995</td>
</tr>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAdyenNv">►</td>
<td class="AccountName">Adyen N.v.</td>
<td class="0"></td>
<td class="5">2575497</td>
<td class="25">20199980</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">22775477</td>
</tr>
<tr class="pool-items collapse hidden idAdyenNv">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000778343</td>
<td class="0"></td>
<td class="5">2575497</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">2575497</td>
</tr>
<tr class="pool-items collapse hidden idAdyenNv">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000872048</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">20199980</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">20199980</td>
</tr>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAllianzDeutschlandAg">►</td>
<td class="AccountName">Allianz Deutschland Ag</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">4039996</td>
<td class="50">19240481</td>
<td class="80"></td>
<td class="GrandTotal">23280477</td>
</tr>
<tr class="pool-items collapse hidden idAllianzDeutschlandAg">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000764304</td>
<td class="0"></td>
<td class="5"></td>
<td class="25"></td>
<td class="50">19240481</td>
<td class="80"></td>
<td class="GrandTotal">19240481</td>
</tr>
<tr class="pool-items collapse hidden idAllianzDeutschlandAg">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000818151</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">4039996</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">4039996</td>
</tr>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAmadeusDataProcessingGmbh">►</td>
<td class="AccountName">Amadeus Data Processing Gmbh</td>
<td class="0"></td>
<td class="5">1009999</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1009999</td>
</tr>
<tr class="pool-items collapse hidden idAmadeusDataProcessingGmbh">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000839743</td>
<td class="0"></td>
<td class="5">1009999</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1009999</td>
</tr>
</tbody>
</table>

Upvotes: 3

Views: 379

Answers (1)

Lajos Arpad
Lajos Arpad

Reputation: 76593

You detach the main rows (except the first) and add them back in the correct order, but you do not detach the inner rows. So, this is what actually happens:

  • you detach all the main rows, except the first -> your first main row remains, followed by all the inner rows, independently of which collapsable rows they belong to
  • you sort the rows starting from the second (why don't you include the first?)
  • you add back the main records in the correct order -> your initial first main row is followed by the inner rows of any main row, then the sorted main rows

This is how your table looks alike after the sort if we don't hide the inner rows:

enter image description here

Fix:

$(document).ready(function() {
// This section for Collapse/Expand feature to hide/unhide child rows
    $('#pool').on('click', 'tbody > tr > .collapsed', function() {
        const collapsed = $(this);
        const accountName = $(this).siblings('.AccountName').text().replace(/[^a-z0-9]/gi, '');
        const trItem = $(this).parents('tr').siblings('.id' + accountName);
        
        trItem.each(function() {
            if($(this).hasClass("hidden")) {
                collapsed.text('▼');
                $(this).removeClass('hidden');
            } else {
                collapsed.text('►');
                $(this).addClass('hidden');
            }
        });
    });
    
// !!!!!!the issue starts here
// This section is for sorting the parents row based on Grand Total column from highest to lowest

 // get rows as array and detach them from the table
var rows = $('#pool tr.accountLevelLine').detach();
let innerRows = $('#pool tr.pool-items').detach();
// sort the parents rows by number in the td with class "GrandTotal"
rows.sort(function (row1, row2) { 
    return parseInt($(row1).find('td.GrandTotal').text()) - parseInt($(row2).find('td.GrandTotal').text());
}); 
// add each row back to the table in the sorted order
rows.each(function () { 
    $(this).appendTo('#pool');
    let that = $(this);
    innerRows.each(function() {
        if ($(this).hasClass(that.find('td:first').data('target').substring(1))) $(this).appendTo('#pool');
    });
});


    
});
table, th, td {
        border: 1px solid;
    }

    .collapsed {
        cursor: pointer;
    }

    .hidden {
        display:none;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="nowrap table table-hover table-bordered" id="pool">
<thead>
<tr class="collapsed">
<th></th>
<th>Account Name</th><th>0</th><th>5</th><th>25</th><th>50</th><th>80</th><th>Grand Total</th>   </tr>
</thead>
<tbody>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAccountantGeneral">►</td>
<td class="AccountName">Accountant General</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">1300000</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1300000</td>
</tr>
<tr class="pool-items collapse hidden idAccountantGeneral">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000733349</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">1300000</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1300000</td>
</tr>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAenaSmeSa">►</td>
<td class="AccountName">Aena S.m.e. Sa.</td>
<td class="0"></td>
<td class="5">6059994</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">6059994</td>
</tr>
<tr class="pool-items collapse hidden idAenaSmeSa">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000759948</td>
<td class="0"></td>
<td class="5">1009999</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1009999</td>
</tr>
<tr class="pool-items collapse hidden idAenaSmeSa">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000897454</td>
<td class="0"></td>
<td class="5">5049995</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">5049995</td>
</tr>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAdyenNv">►</td>
<td class="AccountName">Adyen N.v.</td>
<td class="0"></td>
<td class="5">2575497</td>
<td class="25">20199980</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">22775477</td>
</tr>
<tr class="pool-items collapse hidden idAdyenNv">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000778343</td>
<td class="0"></td>
<td class="5">2575497</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">2575497</td>
</tr>
<tr class="pool-items collapse hidden idAdyenNv">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000872048</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">20199980</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">20199980</td>
</tr>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAllianzDeutschlandAg">►</td>
<td class="AccountName">Allianz Deutschland Ag</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">4039996</td>
<td class="50">19240481</td>
<td class="80"></td>
<td class="GrandTotal">23280477</td>
</tr>
<tr class="pool-items collapse hidden idAllianzDeutschlandAg">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000764304</td>
<td class="0"></td>
<td class="5"></td>
<td class="25"></td>
<td class="50">19240481</td>
<td class="80"></td>
<td class="GrandTotal">19240481</td>
</tr>
<tr class="pool-items collapse hidden idAllianzDeutschlandAg">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000818151</td>
<td class="0"></td>
<td class="5"></td>
<td class="25">4039996</td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">4039996</td>
</tr>
<tr class="accountLevelLine">
<td class="collapsed" data-toggle="collapse" data-target=".idAmadeusDataProcessingGmbh">►</td>
<td class="AccountName">Amadeus Data Processing Gmbh</td>
<td class="0"></td>
<td class="5">1009999</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1009999</td>
</tr>
<tr class="pool-items collapse hidden idAmadeusDataProcessingGmbh">
<td class='pool-items-side'></td>
<td class="OpportunityRef">OPP-0000839743</td>
<td class="0"></td>
<td class="5">1009999</td>
<td class="25"></td>
<td class="50"></td>
<td class="80"></td>
<td class="GrandTotal">1009999</td>
</tr>
</tbody>
</table>

Explanation:

  • we sort all rows, including the first
  • we detach the inner rows as well and append them after their parent is appended

Upvotes: 2

Related Questions