fnRowCallback with JSON data source and search match highlighting
fnRowCallback with JSON data source and search match highlighting
CHgsd
Posts: 25Questions: 0Answers: 0
I have recently revisited the project I was working on here: http://datatables.net/forums/discussion/2123/filter-post-processing-and-highlighting/p1
which allowed highlighting of matched text while filtering.
Some new features in DataTables 1.8 allowed me to do a much better task of loading large datasets, most notably bDeferRender which is absolutely brilliant.
The problem which I have run into is that fnRowCallback no longer works and I have been unable to determine why.
The passage is the following:
[code]"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
var settings = this.fnSettings();
var str = settings.oPreviousSearch.sSearch;
var regex = new RegExp( str + "(?!([^<]+)?>)", 'i')
$('td', nRow).each( function (i) {
this.innerHTML = aData[i].replace( regex, function(matched) { return ""+matched+"";} );
} );
return nRow;
},[/code]
The error returned is:[code]aData[i] is null[/code]
I can't help but suspect that this may be due to my moving from using DOM as a source to a JS array, but searching around hasn't yielded any answers.
Would anyone happen to know what may be causing this?
Cheers,
CHgsd
Post Scriptum: I am using 1.8.1
which allowed highlighting of matched text while filtering.
Some new features in DataTables 1.8 allowed me to do a much better task of loading large datasets, most notably bDeferRender which is absolutely brilliant.
The problem which I have run into is that fnRowCallback no longer works and I have been unable to determine why.
The passage is the following:
[code]"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
var settings = this.fnSettings();
var str = settings.oPreviousSearch.sSearch;
var regex = new RegExp( str + "(?!([^<]+)?>)", 'i')
$('td', nRow).each( function (i) {
this.innerHTML = aData[i].replace( regex, function(matched) { return ""+matched+"";} );
} );
return nRow;
},[/code]
The error returned is:[code]aData[i] is null[/code]
I can't help but suspect that this may be due to my moving from using DOM as a source to a JS array, but searching around hasn't yielded any answers.
Would anyone happen to know what may be causing this?
Cheers,
CHgsd
Post Scriptum: I am using 1.8.1
This discussion has been closed.
Replies
The solution was simple enough. I just needed to add a NULL check before the line modifying the innerHTML. Updated working code is as follows:
[code] "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
var settings = this.fnSettings();
var str = settings.oPreviousSearch.sSearch;
var regex = new RegExp( str + "(?!([^<]+)?>)", 'i');
$('td', nRow).each( function (i) {
if (!!aData[i]) {
this.innerHTML = aData[i].replace( regex, function(matched) { return ""+matched+"";} );
}
} );
return nRow;
},[/code]
I didn't fully think through the move from DOM to JSON and that ended up being the cause for the problem. JSON fed directly from a DB can have NULL data if the DB table has fields which can be NULL.
You made me call into question my methodology however and I am now unsure that what I saw as the problem was the problem. It turns out that aData being either empty or NULL exhibits that problem as opposed to NULL as I originally thought.
Also in debugging, I noticed remnant empty filterMatch spans hanging around so I made yet another change. The updated code is as follows:
[code]
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
var settings = this.fnSettings();
var str = settings.oPreviousSearch.sSearch;
if (str != "") {
var regex = new RegExp( str + "(?!([^<]+)?>)", 'i');
$('td', nRow).each( function (i) {
if ((!!aData[i]) {
this.innerHTML = aData[i].replace( regex, function(matched) { return ""+matched+"";} );
}
else {
/*console.log(i);
console.log(aData);
console.log(nRow);
console.log(this.innerHTML);*/
}
} );
}
return nRow;
},
[/code]
Although it appears to work as expected I am happy to hear your critique if something looks like it could be improved.
rather than getting the index from your jquery set, the below code just uses the aData passed in, and 'i' is within the range of aData's indexes.
[code]
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
var settings = this.fnSettings();
var str = settings.oPreviousSearch.sSearch;
var regex = new RegExp( str + "(?!([^<]+)?>)", 'i')
for (i in aData) {
if (!!aData[i]) { // not sure what this is for..
aData[i] = aData[i].replace( regex, function(matched) { return ""+matched+"";} );
}
}
return nRow;
},
[/code]
by the way, what is the "if (!!aData[i])" thing about?
About the indexes being different, it was my belief that the aData array was used to create the 's and that as a result they had the same order and count. From the console.log() calls this also seemed to hold true. I have been away from datatables and js for a while as a whole though so appreciate your corrections.
Finally the !!aData[i] was to recast as a boolean and check for true/false to avoid the null/empty value problems I was having.
Basically the goal of the code and how it was working correctly previously was to highlight whatever matched the filter string. This is why it needs to match on a clean copy each time and use that to rewrite the html. The bug I ran into that prompted all this revisiting was with null/empty values.
The one missing feature I have been unable to resolve is the lack of highlighting when filtering individual columns.
You may be right as well that aData passed in is not tied to the data in the row/column. To get a reference into the actual data there is an interface function fnGetData(nRow).
[code]
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
var settings = this.fnSettings();
var str = settings.oPreviousSearch.sSearch;
var regex = new RegExp( str + "(?!([^<]+)?>)", 'i')
// ditch the aData sent to us and use the data from DataTables for this row
aData = oTable.fnGetData(nRow);
for (i in aData) {
if (!!aData[i]) {
aData[i] = aData[i].replace( regex, function(matched) { return ""+matched+"";} );
}
}
return nRow;
},
[/code]
Thank you again for your continued help and feedback. I really appreciate the dialogue.
I am having trouble adapting your latest code to work for what I am trying to do.
The supplied aData to fnRowCallback is always clean as it is never modified. What does get modified, at least how I was doing it before, is the innerHTML of the given table cell from within nRow.
This allows the highlight/unhighlighting to take place.
I have in the process of this thread resolved the original problem caused by empty/null values which I ran into causing me to start this thread. That being said I have encountered a much more significant problem which I could desperately use your help with if you are still interested. This new problem involves the highlighting code breaking ColVis.
The most up to date version is presently here: http://datatables.net/forums/discussion/comment/23571#Comment_23571
Thanks again!
CHgsd