I created a table in my HTML code. It has 9 columns and 13 rows. It gets filled up completely by a JavaScript loop that fills it with names of people from a few arrays. Howe
You should get an array of rows, each row is an array of cells. That way the validation is much easier. I'm not sure about how you want to show the conflict. In this demo I've just highlight the duplicated cells (conflicted) in red (at least I like this kind of showing conflict rather than modifying the conflicted cells' text).
HTML:
<table>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>1</td><td>5</td><td>6</td></tr>
<tr><td>7</td><td>8</td><td>7</td></tr>
<tr><td>8</td><td>9</td><td>10</td></tr>
</table>
<button>Check constraints</button>
CSS:
td {
width:100px;
height:50px;
border:1px solid black;
}
table {
border:1px solid black;
border-collapse:collapse;
}
td.invalid {
background:red;
}
JS:
$('td').attr('contenteditable',true);
var cell;
function highlight(){
$(arguments).toggleClass('invalid',true);
}
function checkConstraints(e){
//reset style before re-checking
$('td.invalid').toggleClass('invalid');
//get rows as an array of array
var rows = $('tr').map(function(elem,i){
return [$(this).children('td').toArray()];
}).toArray();
//loop through the rows
for(var i = 0; i < rows.length; i++){
cell = {};
for(var j = 0; j < rows[i].length; j++){
var cellText = $(rows[i][j]).text();
if(cell[cellText]) {
highlight(cell[cellText], rows[i][j]);
} else {
cell[cellText] = rows[i][j];
}
if(i < rows.length - 1 &&
cellText == $(rows[i+1][j]).text()){
highlight(rows[i][j],rows[i+1][j]);
}
}
}
}
$('button').click(checkConstraints);
Note that, I set contenteditable
for all the cells (td
), you can edit the cells text to what you want and click the button to test the demo.
You can use the table rows and cells collections for the iteration. The following does a literal comparison of the text content, you may wish to process the text first to "normalise" it in regard to whitespace.
<table id="t0">
<tr><td>foo<td>bar<td>fum</td>
<tr><td>fum<td>bar<td>foo</td>
<tr><td>foo<td>fum<td>fum</td>
</table>
<script>
compareRows(document.getElementById('t0'));
function compareRows(table) {
var row, rows = table.rows;
var cell, cells;
var rowText;
// For each row in the table
for (var i=0, iLen=rows.length; i<iLen; i++) {
row = rows[i];
cells = row.cells;
// Compare the text in each cell
for (var j=0, jLen=cells.length; j<jLen; j++) {
cell = cells[j];
for (var k=0; k<jLen; k++)
if (k != j && cells[k].textContent == cell.textContent) {
// cell text is repeated in current row
console.log('row ' + i + ' cell ' + j + ' text repeated in cell ' + k);
}
// Compare with the text in the cell immediately below (if there is one)
if (i < iLen-2 && cell.textContent == rows[i+1].cells[j].textContent) {
// cell text is repeated in next row
console.log('row ' + i + ' cell ' + j + ' text repeated in row ' + (i+1));
}
}
}
}
</script>
Note that repeated text in a row will be reported twice.
The above uses the textContent property, which may be supported as innerText in some user agents. It also runs about 10 times faster than the jQuery alternative.