MozenRath
MozenRath

Reputation: 10030

How to show diff of two html tables using javascript?

I have a set of tabular data that has changed. Now i have both the data rendered side by side in two html tables. Now I want to highlight the columns that have changed just like in svn file diff.

I tried doing it with this but I need to make it recursive but not sure how:

function CompareTables(table1, table2) {
    var instHasChange = false;
    for (var i = 0; i < table1.rows.length; i++) {

        var changes = RowExists(table2, table1.rows[i].cells[0].innerHTML, table1.rows[i].cells[1].innerHTML);
        if (!changes[0]) {
            table1.rows[i].style.backgroundColor = "yellow";
            instHasChange = true;
        } else if (changes[1]) {
            table1.rows[i].style.backgroundColor = "yellow";
            instHasChange = true;
        }
    }
    for (var i = 0; i < table2.rows.length; i++) {
        var changes = RowExists(table1, table2.rows[i].cells[0].innerHTML, table2.rows[i].cells[1].innerHTML);
        if (!changes[0]) {
            table2.rows[i].style.backgroundColor = "yellow";
            instHasChange = true;
        } else if (changes[1]) {
            table2.rows[i].style.backgroundColor = "yellow";
            instHasChange = true;
        }
    }
    return instHasChange;
}

function RowExists(table, columnName, columnValue) {

    var hasColumnOrChange = new Array(2);
    hasColumnOrChange[0] = false;
    hasColumnOrChange[1] = false;
    for (var i = 0; i < table.rows.length; i++) {
        if (table.rows[i].cells[0].innerHTML == columnName) {
            hasColumnOrChange[0] = true;
            if (table.rows[i].cells[1].innerHTML != columnValue)
                hasColumnOrChange[1] = true;
        }
    }

    return hasColumnOrChange;
}

The above code only works if there are no inner tables inside this table(We represent data of db child tables in that way)

Please help! Thanks!

EDIT

I have found some more code that is valid for a single table but am not sure how to make it work for a table within a table. Posting the code here

    function highLightDiffList() {
        for (var k = 0; k < 8; k++) {
            var mkrTname = 'table3' + k;
            var actTname = 'table4' + k;
            var makerTr = document.getElementById(mkrTname).childNodes;
            var actualTr = document.getElementById(actTname).childNodes;
            var makerStateLen = makerTr.length;
            var actualStateLen = actualTr.length;
            var actualState = 1;
            var makerState = 1;
            if (makerStateLen > 1)
                makerState = makerTr.item(1).childNodes.item(0).childNodes;
            if (actualStateLen > 1)
                actualState = actualTr.item(1).childNodes.item(0).childNodes;
            var makerTh = document.getElementById(mkrTname).getElementsByTagName("TH").length;
            var minLen;
            var maxLen;
            var flag;
            if (makerStateLen > actualStateLen) {
                minLen = actualStateLen;
                maxLen = makerStateLen;
                flag = 1;
            } else {
                minLen = makerStateLen;
                maxLen = actualStateLen;
                flag = 2;
            }
            for (var i = 1; i < minLen; i++) {
                for (var j = 0; j < makerTh; j++) {
                    if (makerTr.item(i).childNodes.item(0).childNodes.item(j).innerHTML != actualTr.item(i).childNodes.item(0).childNodes.item(j).innerHTML) {
                        makerTr.item(i).childNodes.item(0).childNodes.item(j).style.backgroundColor = document.getElementById('cColor').value;
                        actualTr.item(i).childNodes.item(0).childNodes.item(j).style.backgroundColor = document.getElementById('cColor').value;
                    }
                }
            }
            for (var i = minLen; i < maxLen; i++) {
                for (var j = 0; j < makerTh; j++) {
                    if (flag == 1)
                        makerTr.item(i).style.backgroundColor = document.getElementById('adColor').value;
                    if (flag == 2)
                        actualTr.item(i).style.backgroundColor = document.getElementById('adColor').value;
                }
            }
        }
    }

    function highLightDiff() {
        for (var j = 0; j < 6; j++) {
            var mkrTname = 'table1' + j;
            var actTname = 'table2' + j;

            var makerTr = document.getElementById(mkrTname);
            var actualTr = document.getElementById(actTname);

            var makerStateLen = makerTr.childNodes.item(1).childNodes.length;
            var actualStateLen = actualTr.childNodes.item(1).childNodes.length;

            var makerState = makerTr.childNodes.item(1).childNodes;
            var actualState = actualTr.childNodes.item(1).childNodes;
            for (var i = 1; i < makerStateLen; i++) {
                if (makerState.item(i).childNodes.item(1).innerHTML != '' && actualState.item(i).childNodes.item(1).innerHTML == '') {
                    makerState.item(i).childNodes.item(1).style.backgroundColor = document.getElementById('adColor').value;
                    actualState.item(i).childNodes.item(1).style.backgroundColor = document.getElementById('adColor').value;
                } else {
                    if (makerState.item(i).childNodes.item(1).innerHTML == '' && actualState.item(i).childNodes.item(1).innerHTML != '') {
                        makerState.item(i).childNodes.item(1).style.backgroundColor = document.getElementById('adColor').value;
                        actualState.item(i).childNodes.item(1).style.backgroundColor = document.getElementById('adColor').value;
                    } else {
                        if (makerState.item(i).childNodes.item(1).innerHTML != actualState.item(i).childNodes.item(1).innerHTML) {
                            makerState.item(i).childNodes.item(1).style.backgroundColor = document.getElementById('cColor').value;
                            actualState.item(i).childNodes.item(1).style.backgroundColor = document.getElementById('cColor').value;
                        }
                    }
                }
            }
        }
    }

The inner table is created in the following manner:

<table>
    <tbody>
        <tr>
            <td>
                <div>
                    <table>
                        <tbody>
                            <tr>
                                <td>

Upvotes: 2

Views: 3097

Answers (2)

JoseTeixeira
JoseTeixeira

Reputation: 1306

function CompareTables(table1, table2) {
    var instHasChange = false;
    for (var i = 0; i < table1.rows.length; i++) {
        if (table1.rows[i].cells[0].innerHTML.indexOf('div') != -1) {
            //call CompareTables with inner table
            CompareTables(table1.rows[i].cells[0].childNodes[0].childNodes[0], table2);
        }
        else {
            var changes = RowExists(table2, table1.rows[i].cells[0].innerHTML, table1.rows[i].cells[1].innerHTML);
            if (!changes[0]) {
                table1.rows[i].style.backgroundColor = "yellow";
                instHasChange = true;
            } else if (changes[1]) {
                table1.rows[i].style.backgroundColor = "yellow";
                instHasChange = true;
            }
        }
    }
    return instHasChange;
}

function RowExists(table, columnName, columnValue) {

    var hasColumnOrChange = new Array(2);
    hasColumnOrChange[0] = false;
    hasColumnOrChange[1] = false;
    for (var i = 0; i < table.rows.length; i++) {
        if (table.rows[i].cells[0].innerHTML.indexOf('div') != -1) {
            //call RowExists with inner table
            hasColumnOrChange = RowExists(table.rows[i].cells[0].childNodes[0].childNodes[0], columnName, columnValue);
        }
        else {
            if (table.rows[i].cells[0].innerHTML == columnName) {
                hasColumnOrChange[0] = true;
                if (table.rows[i].cells[1].innerHTML != columnValue)
                    hasColumnOrChange[1] = true;
            }
        }
        //finish for loop if name was found
        if (hasColumnOrChange[0] == true)
            break;
    }

    return hasColumnOrChange;
}

Not tested but should work. might just have to add or remove another .childNodes[0] (or firstChild) if it is not exactly matching with the inner table.
Then you just have to call CompareTables(table1, table2) twice. Once with (table1, table2) and once with (table2, table1).

Upvotes: 1

darkliquid
darkliquid

Reputation: 4109

You might find it easier to do an actual textual diff on the inner table's HTML, then using the information from that to derive which cells have been changed/added/etc. For example, if you take each table's raw HTML (extract via innerHTML or whatever), make sure each opening tag and closing tag is on it's own line, you can then look for new/modified lines and map them back to cells based on the line number.

There are a few javascript diff implementations. You could also look at Dom-diff which is an implementation of a DOM-level diffing system that you may be able to make use of.

Upvotes: 1

Related Questions