deferRender compatibility with columns.render?
deferRender compatibility with columns.render?
Loren Maxwell
Posts: 464Questions: 113Answers: 10
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.rendercalled for the different orthogonal data types. Update the console log statement like this to see the types:The output with
25is thedisplayoperation. 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
createdRowworkaround, 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
createdRowis 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
renderand checking fortype === 'display'and only perform the handlebars templating under that condition.If it is, the another other with
renderwould be to cache the result. Use the row and cell index from themetaobject 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.typeto a custom type,site-link:Then using a global DataTables
drawI 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.typeassite-linkand only have to maintain the one globaldrawfor all tables on the entire site3) avoiding a potential conflict with
createdRowwhen 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.typeofsite-linkthat 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.