Abhishek Mahale Abhishek Mahale - 1 month ago 8
Javascript Question

Sorting two similar tables simultaneously

I've two tables which has exactly same columns. These tables are placed besides each other. Currently they are sorted separately. I want them to be sorted together. i.e. when I click on first column header of table 1 both tables should be sorted as if both are a single table.

This is the .js which I am using

function SortableTable (tableEl) {

this.tbody = tableEl.getElementsByTagName('tbody');
this.thead = tableEl.getElementsByTagName('thead');
this.tfoot = tableEl.getElementsByTagName('tfoot');

this.getInnerText = function (el) {
if (typeof(el.textContent) != 'undefined') return el.textContent;
if (typeof(el.innerText) != 'undefined') return el.innerText;
if (typeof(el.innerHTML) == 'string') return el.innerHTML.replace(/<[^<>]+>/g,'');
}

this.getParent = function (el, pTagName) {
if (el == null) return null;
else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())
return el;
else
return this.getParent(el.parentNode, pTagName);
}

this.sort = function (cell) {

var column = cell.cellIndex;
var itm = this.getInnerText(this.tbody[0].rows[1].cells[column]);
var sortfn = this.sortCaseInsensitive;

if (itm.match(/\d\d[-]+\d\d[-]+\d\d\d\d/)) sortfn = this.sortDate; // date format mm-dd-yyyy
if (itm.replace(/^\s+|\s+$/g,"").match(/^[\d\.]+$/)) sortfn = this.sortNumeric;

this.sortColumnIndex = column;

var newRows = new Array();
for (j = 0; j < this.tbody[0].rows.length; j++) {
newRows[j] = this.tbody[0].rows[j];
}

newRows.sort(sortfn);

if (cell.getAttribute("sortdir") == 'down') {
newRows.reverse();
cell.setAttribute('sortdir','up');
} else {
cell.setAttribute('sortdir','down');
}

for (i=0;i<newRows.length;i++) {
this.tbody[0].appendChild(newRows[i]);
}

}

this.sortCaseInsensitive = function(a,b) {
aa = thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]).toLowerCase();
bb = thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]).toLowerCase();
if (aa==bb) return 0;
if (aa<bb) return -1;
return 1;
}

this.sortDate = function(a,b) {
aa = thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]);
bb = thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]);
date1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);
date2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);
if (date1==date2) return 0;
if (date1<date2) return -1;
return 1;
}

this.sortNumeric = function(a,b) {
aa = parseFloat(thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]));
if (isNaN(aa)) aa = 0;
bb = parseFloat(thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]));
if (isNaN(bb)) bb = 0;
return aa-bb;
}

// define variables
var thisObject = this;
var sortSection = this.thead;

// constructor actions
if (!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length > 0)) return;

if (sortSection && sortSection[0].rows && sortSection[0].rows.length > 0) {
var sortRow = sortSection[0].rows[0];
} else {
return;
}

for (var i=0; i<sortRow.cells.length; i++) {
sortRow.cells[i].sTable = this;
sortRow.cells[i].onclick = function () {
this.sTable.sort(this);
return false;
}
}

}


There are just two columns and are likely to remain the same. Some ideas would be really appreciated.

Answer

I don't quite follow the HTML you have (since you didn't include any HTML), so I created a simple version myself here and implemented a sort across tables. The basic idea is that it collects all the data out of the tables into a single javascript data structure, sorts the javascript data structure and then puts all the data back into the tables.

This makes the sorting much simpler and the only places you have to deal with the complexities of multiple tables is when retrieving the data and then putting it back into the tables. You can see it work here: http://jsfiddle.net/jfriend00/Z5ywA/. Just click on a column header to see both tables sorted by that column.

The code is this:

function sortTables(colNum) {
    var t1 = document.getElementById("table1");
    var t2 = document.getElementById("table2");
    var data = [], sortFn;

    function sortAlpha(a, b) {
        // deal with empty strings
        var aa = a[colNum].data, bb = b[colNum].data;
        if (!aa) {
            return(!bb ? 0 : -1);
        } else if (!bb){
            return(1);
        } else {
            return(aa.localeCompare(bb));
        }
    }

    function sortNumeric(a, b) {
        // deal with possibly empty strings
        var aa = a[colNum].data, bb = b[colNum].data;
        if (typeof aa == "string" || typeof bb == "string") {
            return(sortAlpha(a, b));
        } else {
            return(aa - bb);
        }
    }

    // get the data
    function getData(table) {
        var cells, rowData, matches, item, cellData;
        var rows = table.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
        for (var i = 0; i < rows.length; i++) {
            rowData = [];
            cells = rows[i].getElementsByTagName("td");
            for (var j = 0; j < cells.length; j++) {
                // add each cell in the row to the rowData data structure
                item = {};
                item.origStr = cells[j].textContent || cells[j].innerText;
                cellData = item.origStr.replace(/^\s*|\s*$/g, "").toLowerCase();
                if (cellData.match(/^[\d\.]+$/)) {
                    cellData= parseFloat(cellData);
                } else if (matches = cellData.match(/^(\d+)-(\d+)-(\d+)$/)) {
                    cellData= new Date(
                        parseInt(matches[3], 10), 
                        parseInt(matches[1], 10) - 1, 
                        parseInt(matches[2], 10)
                    );
                }
                item.data = cellData;
                // determine the type of sort based on the first cell we find 
                // with data in the column that we're sorting
                if (!sortFn && item.data !== "" && j == colNum) {
                    if (typeof item.data == "number" || typeof item.data == "object") {
                        sortFn = sortNumeric;
                    } else {
                        sortFn = sortAlpha;
                    }
                }
                rowData.push(item);
            }
            // add each row to the overall data structure
            data.push(rowData);
        }
    }

    // put data back into the tables
    function putData(table) {
        var cells, rowData, item;
        var rows = table.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
        for (var i = 0; i < rows.length; i++) {
            cells = rows[i].getElementsByTagName("td");
            for (var j = 0; j < cells.length; j++) {
                // add each cell in the row to the rowData data structure
                cells[j].innerHTML = data[0][j].origStr;
            }
            // remove this row
            data.shift();
        }
    }


    getData(t1);
    getData(t2);
    data.sort(sortFn);
    putData(t1);
    putData(t2);        

    return(false);
}

​ ​