deferRender compatibility with columns.render?
deferRender compatibility with columns.render?

My understanding is that deferRender
holds off on rendering rows until they are displayed in the table and that it is default to true
in DataTables 2.0.
I have the following table with 4,237 rows:
var dt_coaches_index = $('#dt-coaches-index').DataTable({
... blah blah blah ...
columns: [
{
title: 'Coach',
data: 'person_link',
render: function ( data, type, row, meta ) {
return hbs('hbs-site-link', data) // Handlebars template
}
}
]
})
This takes anywhere from between 10 and 12 seconds, which seemed excessive so I started to troubleshoot my query, but it only takes about 0.15 seconds to generate and seems to be optimized in itself.
Then I tried without the Handlebars template:
{
title: 'Coach',
data: 'person_link'
}
And the table renders quickly as expected.
So it seemed to be an issue with my Handlebars template or when using columns.render
.
I added a troubleshooting line to write to the console whenever the row is rendered:
var dt_coaches_index = $('#dt-coaches-index').DataTable({
... blah blah blah ...
columns: [
{
title: 'Coach',
data: 'person_link',
render: function ( data, type, row, meta ) {
console.log('row render called') // Troubleshooting
}
}
]
})
And was surprised to see that the render is called three times for each cell even though deferRender
is set to true
:
Am I misunderstanding deferRender
? Or it's compatibility with columns.render
?
Separately, when I do this workaround using the createdRow
callback to achieve what I thought deferRender
was meant to do, it's probably less than a half second total for 25 rows, which I would expect, so I don't think it's the Handlebars template:
var dt_coaches_index = $('#dt-coaches-index').DataTable({
... blah blah blah ...
columns: [
{
title: 'Coach',
data: 'person_link',
className: 'person-link' // 'person-link'
}
],
createdRow: function (row, data, dataIndex, cells) {
var cellElement = $('.person-link', row) // Find 'person-link'
if (cellElement.length) {
cellElement.html(hbs('hbs-site-link', data.person_link)) // Update
}
}
})
This question has an accepted answers - jump to answer
Answers
What you see is expected behavior. You are seeing
columns.render
called for the different orthogonal data types. Update the console log statement like this to see the types:The output with
25
is thedisplay
operation. See if this helps the timing:This will call the handlebars template only when the cell data is displayed. This will have the side affect of not having the handlebars data as part of sorting and searching.
Kevin
Ahhh -- I knew I had to be overlooking something!
Many thanks for the explanation, @kthorngren!
I'm adding this small note for anyone interested --
I've updated my render as per @kthorngren's post and while it has significantly reduced the time from 10 to 12 seconds to around a second or so, it is still not nearly as quick as the
createdRow
workaround, which is nearly instantaneous.There may be other issues with that approach, but I thought noting the speed difference might still be helpful.
Yeah, there are trade-offs to the two approaches. The primary disadvantage of
createdRow
is that DataTables won't "see" the changes that you make to the display data. So if your end user were to search on that data, it wouldn't match the modified rendering - it would still be searching the original data. The same with ordering.That might or might not be an issue.
If it isn't then you could consider using
render
and checking fortype === 'display'
and only perform the handlebars templating under that condition.If it is, the another other with
render
would be to cache the result. Use the row and cell index from themeta
object to save the result into an object. Then have the rendering function check if there is already a cached result, and if so, use it, if not, create and cache it.Of course, if the data changes, then cache brings its own complications (two problems in computer science...), but that would be one of the most optimal approaches while allowing the data to be searched and sorted.
Allan
Just wanted to show my solution for anyone interested (and willing to critique) . . .
My site is full of tables with links using a custom Handlebars 'site-link' template:
For those columns I set the
columns.type
to a custom type,site-link
:Then using a global DataTables
draw
I find those columns and update those cells:If you needed the row data for some reason you could use do this:
This seems to work well for me because of:
1) the (much) increased speed
2) the cleaner code (only have to specify the column is
columns.type
assite-link
and only have to maintain the one globaldraw
for all tables on the entire site3) avoiding a potential conflict with
createdRow
when overriding DataTables defaultsThat being said -- I'm not worried about the potential filtering or ordering issues that @allan mentioned in the post above, so I think it would work for most folks but might not for all.
There's also a risk that @allan could introduce a future
columns.type
ofsite-link
that would cause a conflict, but I'm thinking that's unlikelyYup, very unlikely I'd say
.
Many thanks for the write up - it looks like a good solution (taking account of the issues you mention).
I do like handlebars - its nice to see this integration
Allan
Yeah, Handlebars has been almost as impactful as DataTables and Editor for me.
It has greatly simplified things and made my site much more consistent looking.
I can't see doing anything without it (or some templating library) in the future.