Skip to content

Why are all tables sorted although only the first one is clicked?

I am creating a custom table for my application, which is sortable. The problem comes when i have multiple sortable tables.

The sorting of the last table works fine, but when I click on the first table header all the other tables also gets sorted.

All the sorting and filtering I did is inside the below library

var IlForCustomTables = IlForCustomTables || {};

I just want to know why other tables are getting sorted when I click on the first table, and how I can solve this.

var IlForCustomTables = IlForCustomTables || {};
IlForCustomTables = {
  //Basic Table
  BindTableDataBasic: function(DivId, Headers, Body, startIndex) {
    for (let i = 0; i < Body.length; i++) {
      $('#' + DivId).find('.tbody').append('<tr class="tbody' + i + '"></tr>');
      for (let a = 0; a < Headers.length; a++) {
        if (a < startIndex)
          $('#' + DivId).find('.tbody').find('.tbody' + i).append('<td></td>');
        else
          $('#' + DivId).find('.tbody').find('.tbody' + i).append('<td>' + Body[i][Headers[a].replace(/ /g, '')] + '</td>');
      }
    }
  },

  BindCustomTable: function(DivId, Headers, Body, startIndex, filter, sorting) {
    let filterInput = '';
    if (filter)
      filterInput = '<input type="text" class="filterInput" />';
    $('#' + DivId).append(filterInput + '<div class="table-responsive"><table class="table table-bordered"><thead><tr class="thead"></tr></thead><tbody class="tbody tbody_' + DivId + '"></tbody></table></div>');
    for (let i = 0; i < Headers.length; i++) {
      $('#' + DivId).find('.thead').append('<th class="SortTableHeader">' + Headers[i] + '</th>');
    }
    IlForCustomTables.BindTableDataBasic(DivId, Headers, Body, startIndex);
    if (sorting)
      $('.SortTableHeader').click(function() {
        IlForCustomTables.CustomSorting(DivId, $(this).index());
      });
    if (filter)
      $('.filterInput').keyup(function() {
        IlForCustomTables.CustomFilter(DivId);
      });
  },

  CustomFilter: function(DivId) {
    var input, filter, table, tr, td, i, txtValue;
    input = $('#' + DivId).find('.filterInput');
    filter = input.val().toUpperCase();
    table = $('#' + DivId).find('.table');
    tr = table.find('.tbody').find('tr');
    for (i = 0; i < tr.length; i++) {
      let found = false;
      for (let a = 0; a < tr[i].getElementsByTagName("td").length; a++) {
        td = tr[i].getElementsByTagName("td")[a];
        if (td) {
          txtValue = td.textContent || td.innerText;
          if (txtValue.toUpperCase().indexOf(filter) > -1) {
            tr[i].style.display = "";
            found = true;
          }
        }
      }
      if (!found)
        tr[i].style.display = "none";
    }
  },

  CustomSorting: function(DivId, index) {
    const table = $('.tbody_' + DivId)[0];
    Array.from(table.querySelectorAll('tr:nth-child(n+1)'))
      .sort(comparer(index, this.asc = !this.asc))
      .forEach(tr => table.appendChild(tr));
  }
}

const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent;

const comparer = (idx, asc) => (a, b) => ((v1, v2) =>
  v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
)(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));


const TableHeader = ['Action', 'Id', 'Name', 'Age', 'Area Name', ' Work Experience'];
const TableHeader1 = ['Action', 'Id', 'Full Name', 'Current Age', 'Native Place', ' Work Experience'];
const TableData = [{
    'Id': '1',
    'Name': 'Ibrahim',
    'Age': '27',
    'AreaName': 'Wadala',
    'WorkExperience': '5'
  },
  {
    'Id': '2',
    'Name': 'Rohit',
    'Age': '30',
    'AreaName': 'Kalyan',
    'WorkExperience': '6'
  },
  {
    'Id': '3',
    'Name': 'Kunal',
    'Age': '32',
    'AreaName': 'Andheri',
    'WorkExperience': '7'
  },
  {
    'Id': '4',
    'Name': 'Yogesh',
    'Age': '38',
    'AreaName': 'Borivali',
    'WorkExperience': '8'
  },
  {
    'Id': '5',
    'Name': 'Varun',
    'Age': '36',
    'AreaName': 'Seawoods',
    'WorkExperience': '9'
  },
];

const TableData1 = [{
    'Id': '1',
    'FullName': 'Ibrahim S',
    'CurrentAge': '27',
    'NativePlace': 'Bangalore',
    'WorkExperience': '5'
  },
  {
    'Id': '2',
    'FullName': 'Rohit D',
    'CurrentAge': '30',
    'NativePlace': 'Pune',
    'WorkExperience': '6'
  },
  {
    'Id': '3',
    'FullName': 'Kunal D',
    'CurrentAge': '32',
    'NativePlace': 'Gujarat',
    'WorkExperience': '7'
  },
  {
    'Id': '4',
    'FullName': 'Yogesh R',
    'CurrentAge': '38',
    'NativePlace': 'Kankavali',
    'WorkExperience': '8'
  },
  {
    'Id': '5',
    'FullName': 'Varun S',
    'CurrentAge': '36',
    'NativePlace': 'Gujarat',
    'WorkExperience': '9'
  },
];
$(document).ready(function() {
  IlForCustomTables.BindCustomTable('ICGrid3', TableHeader1, TableData1, 1, false, true);
  IlForCustomTables.BindCustomTable('ICGrid4', TableHeader1, TableData1, 1, true, true);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="ICGrid1"></div>
<div id="ICGrid2"></div>
<div id="ICGrid3"></div>
<div id="ICGrid4"></div>

Here is my Fiddle for the above code.

Answer

In your click handlers you select all .SortTableHeader and therefor the action for each div is bound to each header. You have to specify which header is meant:

$('#' + DivId + ' .SortTableHeader').click(function() {...]);

Working example:

var IlForCustomTables = IlForCustomTables || {};
IlForCustomTables = {
  //Basic Table
  BindTableDataBasic: function(DivId, Headers, Body, startIndex) {
    for (let i = 0; i < Body.length; i++) {
      $('#' + DivId).find('.tbody').append('<tr class="tbody' + i + '"></tr>');
      for (let a = 0; a < Headers.length; a++) {
        if (a < startIndex)
          $('#' + DivId).find('.tbody').find('.tbody' + i).append('<td></td>');
        else
          $('#' + DivId).find('.tbody').find('.tbody' + i).append('<td>' + Body[i][Headers[a].replace(/ /g, '')] + '</td>');
      }
    }
  },

  BindCustomTable: function(DivId, Headers, Body, startIndex, filter, sorting) {
    let filterInput = '';
    if (filter)
      filterInput = '<input type="text" class="filterInput" />';
    $('#' + DivId).append(filterInput + '<div class="table-responsive"><table class="table table-bordered"><thead><tr class="thead"></tr></thead><tbody class="tbody tbody_' + DivId + '"></tbody></table></div>');
    for (let i = 0; i < Headers.length; i++) {
      $('#' + DivId).find('.thead').append('<th class="SortTableHeader">' + Headers[i] + '</th>');
    }
    IlForCustomTables.BindTableDataBasic(DivId, Headers, Body, startIndex);
    if (sorting)
      $('#' + DivId + ' .SortTableHeader').click(function() {
        IlForCustomTables.CustomSorting(DivId, $(this).index());
      });
    if (filter)
      $('.filterInput').keyup(function() {
        IlForCustomTables.CustomFilter(DivId);
      });
  },

  CustomFilter: function(DivId) {
    var input, filter, table, tr, td, i, txtValue;
    input = $('#' + DivId).find('.filterInput');
    filter = input.val().toUpperCase();
    table = $('#' + DivId).find('.table');
    tr = table.find('.tbody').find('tr');
    for (i = 0; i < tr.length; i++) {
      let found = false;
      for (let a = 0; a < tr[i].getElementsByTagName("td").length; a++) {
        td = tr[i].getElementsByTagName("td")[a];
        if (td) {
          txtValue = td.textContent || td.innerText;
          if (txtValue.toUpperCase().indexOf(filter) > -1) {
            tr[i].style.display = "";
            found = true;
          }
        }
      }
      if (!found)
        tr[i].style.display = "none";
    }
  },

  CustomSorting: function(DivId, index) {
    const table = $('.tbody_' + DivId)[0];
    Array.from(table.querySelectorAll('tr:nth-child(n+1)'))
      .sort(comparer(index, this.asc = !this.asc))
      .forEach(tr => table.appendChild(tr));
  }
}

const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent;

const comparer = (idx, asc) => (a, b) => ((v1, v2) =>
  v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
)(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));


const TableHeader = ['Action', 'Id', 'Name', 'Age', 'Area Name', ' Work Experience'];
const TableHeader1 = ['Action', 'Id', 'Full Name', 'Current Age', 'Native Place', ' Work Experience'];
const TableData = [{
    'Id': '1',
    'Name': 'Ibrahim',
    'Age': '27',
    'AreaName': 'Wadala',
    'WorkExperience': '5'
  },
  {
    'Id': '2',
    'Name': 'Rohit',
    'Age': '30',
    'AreaName': 'Kalyan',
    'WorkExperience': '6'
  },
  {
    'Id': '3',
    'Name': 'Kunal',
    'Age': '32',
    'AreaName': 'Andheri',
    'WorkExperience': '7'
  },
  {
    'Id': '4',
    'Name': 'Yogesh',
    'Age': '38',
    'AreaName': 'Borivali',
    'WorkExperience': '8'
  },
  {
    'Id': '5',
    'Name': 'Varun',
    'Age': '36',
    'AreaName': 'Seawoods',
    'WorkExperience': '9'
  },
];

const TableData1 = [{
    'Id': '1',
    'FullName': 'Ibrahim S',
    'CurrentAge': '27',
    'NativePlace': 'Bangalore',
    'WorkExperience': '5'
  },
  {
    'Id': '2',
    'FullName': 'Rohit D',
    'CurrentAge': '30',
    'NativePlace': 'Pune',
    'WorkExperience': '6'
  },
  {
    'Id': '3',
    'FullName': 'Kunal D',
    'CurrentAge': '32',
    'NativePlace': 'Gujarat',
    'WorkExperience': '7'
  },
  {
    'Id': '4',
    'FullName': 'Yogesh R',
    'CurrentAge': '38',
    'NativePlace': 'Kankavali',
    'WorkExperience': '8'
  },
  {
    'Id': '5',
    'FullName': 'Varun S',
    'CurrentAge': '36',
    'NativePlace': 'Gujarat',
    'WorkExperience': '9'
  },
];
$(document).ready(function() {
  IlForCustomTables.BindCustomTable('ICGrid3', TableHeader1, TableData1, 1, false, true);
  IlForCustomTables.BindCustomTable('ICGrid4', TableHeader1, TableData1, 1, true, true);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="ICGrid1"></div>
<div id="ICGrid2"></div>
<div id="ICGrid3"></div>
<div id="ICGrid4"></div>