0

I need to implement a functionality in jquery where a user clicks on very first row and sort remaining items in clicked row. I've prepared a codepen here https://codepen.io/shaikh709/pen/orNLaY?editors=0010

Here is the js I've for sorting table

function sortRow(rowIndex) {

    let table               = $('.report')
    let tr                  = table.find('tr');
    let selectedRow         = $(tr[rowIndex]);
    let selectedRowTd       = selectedRow.find('td');
    let selectedRowSorting  = [];

    // find and get clicked tr and it formats it in index and value of the cells
    selectedRowTd.each(function(tdIndex){
        let td = $(selectedRowTd[tdIndex]);
        selectedRowSorting.push({
            tdIndex: tdIndex,
            value: parseInt(Math.ceil(td.text().trim()))
        })
    })


    // it will compare values and sort
    selectedRowSorting = selectedRowSorting.sort(function(a, b){

        if (a.value == 0) {
            return -1;
        }

        if (b.value == 0) {
            return -1;
        }

        return b.value - a.value
    });

    console.log(selectedRowSorting)

    // it will only return indexs of sorted list of cells
    var sortedIndexs = selectedRowSorting.map(function(rowSorting){
        return rowSorting.tdIndex
    })

    console.log(sortedIndexs)

    table.find('tr').each(function(){
        let tr = $(this);
        let modifiedTr = [];

        tr.children().each(function(tdIndex, td){

          if (tdIndex == 0) {
            console.log(td)           
            modifiedTr[0] = td;

          } else {
            for (let i =0; i < sortedIndexs.length;i++) {
              console.log(sortedIndexs[i])
              // it gives me index of sorted column.
              if (tdIndex == i) {
                let sortedIndex = sortedIndexs[i];

                if ( sortedIndex == undefined) {
                  console.log('i', i, sortedIndex)
                  sortedIndex = sortedIndexs.length+1
                }

                modifiedTr[sortedIndex] = td;
              }
            }
          }

        })

        tr.append(modifiedTr)
    })
}

I've created a demo here https://codepen.io/shaikh709/pen/orNLaY?editors=0010

When user click on first (very left) cell in a row. I want rest of the row to switch to largest to smallest value.

Been stuck here for about couple of days. Any help is appreciated. Thanks. :)

prinkpan
  • 2,117
  • 1
  • 19
  • 32

1 Answers1

1

I would keep it simple and just build a small Array of the values, and then use .sort() upon the Array.

Working Example: https://jsfiddle.net/Twisty/ondf3ram/

JavaScript

$(function() {
  function sortDesc(a, b) {
    return a - b;
  }

  function sortAsc(a, b) {
    return b - a;
  }

  function sortRow(rObj, desc) {
    var curArr = [];
    $("td", rObj).each(function(i, el) {
      curArr.push(parseInt($(el).text().trim()));
    });
    if (desc == undefined || desc == true) {
      curArr.sort(sortDesc);
    } else {
      curArr.sort(sortAsc);
    }
    $("td", rObj).each(function(i, el) {
      $(el).html(curArr[i]);
    });
  }

  $(".sortable tbody th").on("click", function(e) {
    var r = $(this).parent();
    if ($(this).data("sort") == undefined) {
      $(this).data("sort", true);
    }
    sortRow(r, $(this).data("sort"));
    $(this).data("sort", $(this).data("sort") ? false : true);
  });
});

Making use of the proper Selectors will help you a lot! I wasn't sure if you wanted to reverse the sort Descending to Ascending. So here are the goals I went for:

  • Click on <th> (first) cell in the <tbody> to execute a sort of the parent <tr>
  • Initially sort with Descending Sort
  • Additional clicks will toggle the sort from Desc. to Asc.

To this effect we have the sortRow() function that expects a jQuery <tr> Object. Optionally it can accept a sort Direction as a Boolean (Default: true, true = Desc. / false = Asc). It performs the sort and does not return anything.

I created an Array and populated it using the .each() function to iterate over each <td> in the <tr> that is targeted. Since I am getting the .text() or Text node of the cell, I use .trim() to drop any white space and then use parseInt() to populate the Array with Integers.

We then Sort the Array based on compare function:

A function that defines an alternative sort order. The function should return a negative, zero, or positive value, depending on the arguments.

We then re-iterate the same cells and replace the content from the array. All done!

I added the toggle feature by looking for .data() on each row. If this is the first click, there will be no data, so we assume a Desc. sort. The next time we click on that row header, it will have a value and toggle to an Asc. sort.

Update

Base don your comments, it sounds like you want to sort a Martix. This is discussed here: How to sort 2 dimensional array by column value?

Working Example: https://jsfiddle.net/Twisty/ondf3ram/70/

JavaScript

$(function() {

  var selInd;

  function sortMatrixDesc(a, b) {
    if (a[selInd] === b[selInd]) {
      return 0;
    } else {
      return (a[selInd] < b[selInd]) ? -1 : 1;
    }
  }

  function sortMatrixAsc(a, b) {
    if (a[selInd] === b[selInd]) {
      return 0;
    } else {
      return (a[selInd] > b[selInd]) ? -1 : 1;
    }
  }

  function getTblCont(tb) {
    var cols = [];
    $("tr:first td", tb).each(function(i, el) {
      cols[i] = [];
    });
    for (var c = 0; c < cols.length; c++) {
      $("tr", tb).each(function(i, el) {
        cols[c].push(parseInt($("td", el).eq(c).text().trim()));
      });
    }
    return cols;
  }

  function sortRow(rObj, desc) {
    var tblObj = getTblCont(rObj.parent());
    var rowInd = rObj.index();
    if (desc == undefined || desc == true) {
      tblObj.sort(sortMatrixDesc);
    } else {
      tblObj.sort(sortMatrixAsc);
    }
    rObj.parent().find("tr").each(function(r, tr) {
      $("td", tr).each(function(i, el) {
        $(el).html(tblObj[i][r]);
      });
    });
  }

  $(".sortable tbody th").on("click", function(e) {
    var r = $(this).parent();
    selInd = r.index();
    if ($(this).data("sort") == undefined) {
      $(this).data("sort", true);
    }
    sortRow(r, $(this).data("sort"));
    $(this).data("sort", $(this).data("sort") ? false : true);
  });
});

Hope that helps.

Twisty
  • 30,304
  • 2
  • 26
  • 45
  • That's awesome. Thank you. The reason why I built it this way, because Columns must follow the changes. Like in your example only clicked row changes but column header remains same which makes changes invalid because they don't belong to that column. That's the reason I tried to use indexes to manipulate all other columns. Do you have any idea about it? – Sharik Shaikh Jun 11 '19 at 06:52
  • @shariksharikh not sure I understand. You want the columns to sort when you click on a row? – Twisty Jun 11 '19 at 07:09
  • yes, like in your example if you click on row3. Contents of row3 would sort but header (Col1, Col2, etc) remains the same. Which makes data invalid. – Sharik Shaikh Jun 11 '19 at 07:36
  • amazing, That's what I was looking for. I really appreciate it. Thank you very much :) – Sharik Shaikh Jun 11 '19 at 08:34