-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
allow render function to assume direct control of updating cell DOM #425
base: master
Are you sure you want to change the base?
Conversation
This is a quick proof-of-concept patch for the idea of allowing the render function to take full control of rendering content within a cell. Instead of returning HTML for DataTables to add to the cell, the render function updates the DOM directly and returns null to indicate that touching the innerHTML is unnecessary. This allows the view rendering code to retain references to actual dom elements on the page for event handling and UI binding. As an example, my application is using a Backbone Marionette view for each cell's contents, binding the view to the td created by DataTables and then rendering to it directly. I first tried using column.createdCell, which gives convenient access to the cell node, but that the initial drawing; subsequent re-displays only call data and/or display and then overwrite the innerHTML, orphaning the previous elements. I don't really expect this patch to be accepted directly but I wanted to open discussion about providing some method to accomplish direct rendering control. Issues to considering * the td node could be better exposed to the rendering function Right now, I have to dig out of the meta parameter: meta.settings.aoData[meta.row].anCells[meta.col] but it could be passed as a parameter, or perhaps added as e.g. meta.node. Alternatively, the render function could be permitted to create and return the node itself. * a better way to signal that the render function is handling the rendering and that DataTables should not modify innerHTML Using "null" is kinda dirty. Could be signaled by return type (HTMLElement) or by using a different function than column.render which always handles rendering
As an example, my render function looks something like this:
|
Thanks for opening this - it is an interesting area for discussion and one I'm not fully happy with in how DataTables currently implements it, but there are a few reasons why it is done this way. Firstly the Secondly DataTables stores cached information (for speed) about the data for the cell, such as filtering and sorting. If another controller can update the cell directly DataTables wouldn't know about that, and the cached information would be out of date, given (what would look like) random results. The first point is why the cell isn't passed through to the As such I don't really see a way at the moment for an external library to fully control the HTML for a cell. It will likely need a new API (a bit like So yes, I won't pull this in directly, but I would be interested in your further thoughts. |
Thanks for your response, I appreciate hearing from someone with a better understanding of DataTables internals. Regarding your comments: My current method is working with deferRender. The key I spent some time observing when and how Regarding updates, I did run into this issue as well. I am addressing it by creating a listener on each column view's model object which calls Basically, it seems like there is the opportunity for a fairly clean division between the different |
I should really put together a working fiddle or something to demonstrate what I'm doing. |
Ah, okay, I understand the invalidate case better now - invalidate causes immediate |
Yup - the rendering function makes no assumption about when it will be called, although obviously external to it (still internally in DataTables) the various features of the library have their own way of handling it. Complicating it slightly is that I'm planning to add an API that will let developers get the data for each type externally. Not sure how that will work yet but it might be something like |
Okay, that's my understanding about the On that same topic, I'm not exactly clear what you mean in the second paragraph - what do you mean by "type" here? |
Anyway, I put together a simple working example of what I'm doing: http://live.datatables.net/futuwife/9/edit In this example, the Salary column is being rendered with a Backbone.Marionette view. The view also handles controls that modify the value. There's a custom Everything is working afaict - paging, sorting, filtering. Have I missed anything? |
Coincidentally, I just did a pull request #429 regarding this same thing. Please take a look. Taking full control of the td element by passing it (of sorts) seems would be the best scenario if you can get that to work. However, otherwise, my approach will still enable appending and inserting html DOM elements that would maintain their bindings. I'm also using Backbone, and I tested it with my pull request. It works retains the DOM binding. |
The |
There are also some minor issues with |
I linked the wrong revision of my demo, this is the latest: http://live.datatables.net/futuwife/11/edit |
Thanks for the demo - very instructive! This works because you are using the orthogonal data options such that the data can be requested at any time ( It is a few more hoops to jump through than I think the average developer might be willing to make, but this is a change in the core that I am going to consider. Possibly between that, and the invalidation helper you use, being packable in a library, that might make it a bit smoother. I'm not going to drop it in right now because TableTools requests the display data type, as do some other extensions and plug-ins which would break with this pattern. I'm going to look at how to resolve that first. I'm thinking of having a |
+1 for supporting some sort of direct DOM generation. In my case I'm using a component framework which generates DOM explicitly and encapsulates state in components...so it becomes completely unmanageable to separately render the component as a string template. My current approach is to implement |
+1 This would be a useful feature for use with custom controls within a cell which have their own rendering functionality (e.g. a backbone view). |
👍 Using angular and it would be great to be able to pass a rendered DOM element with bindings, etc. |
just a little comment here, was actually looking for sth else about datatables, but since i had same problem about rendering custom row (using framework/template engine etc both in server and client) i do this:
example code (client, but very similar for server) TBApp.appendTable('#projects', columns, [
projectRow.renderBlock("col0", project)
,projectRow.renderBlock("col1", project)
,projectRow.renderBlock("col2", project)
,projectRow.renderBlock("col3", project)
,projectRow.renderBlock("col4", project)
,projectRow.renderBlock("col5", project)
,projectRow.renderBlock("col6", project)
]); template code (same for both client/server) {# #}
{#%block("col0",false)#}{#%widget("checkbox",{"name":$id, "class":"select_row"})#}{#%endblock()#}
{#%block("col1",false)#}<a href="{#%route(''/edit')#}">{#$name#}</a>{#%endblock()#}
{#%block("col2",false)#}{#$cat#}{#%endblock()#}
{#%block("col3",false)#}{#$start#}{#%endblock()#}
{#%block("col4",false)#}{#$end#}{#%endblock()#}
{#%block("col5",false)#}{#%l($status)#}{#%endblock()#}
{#%block("col6",false)#}
{#%widget('link',{'href':%route("/edit"),'icon':'edit'},{'title':%l('Edit')})#}
{#%widget('link',{'href':%route("/display"),'icon':'question-circle'},{'title':%l('Display')})#}
{#%widget('link',{'href':%route("/delete"),'icon':'users'},{'title':%l('Delete')})#}
{#%endblock()#} update the mvc framework i use (again my own modelview.js) does not need to bind to a dom element directly upon generation, it delegates so dynamic elements can be added / remove as needed and / or rendered as strings etc.., yet the mvc functionality can work without problem |
btw the actual issue with datatables that i was looking for was a way to customize the wrapper/filters section not with javascript but at render time (meaning with actual html code before rendering the table withg datatables). Any ideas how to do that?? Thank you very much and kudos for the plugin (use it for data tables since i came accross it) :) |
combining datatables with angular.js (an angular directive for customizabl;e datatable) check this link (stumbled upon it) https://myjitjs.wordpress.com/2013/11/04/data-table-in-angular/ |
+1 for the feature. I'm not using backbone, but just using plain JS i managed to make it work almost as in @pimlottc example (but with dropdown buttons in cells). After first render of the table everything seems perfect. But after any filtering or sorting my tricky-handled cells become empty. My data is server-side processed, but is there a particular reason, why on first load cells are getting filled correctly, but after sorting - empty? Also, as i understand, the main benefit of this feature would be defining proper element with listeners attached. For me it is so, anyways. I tried to avoid this workarounds by using another approach:
Is there a way out of this? Maybe i misunderstand the behaviour of the table on sorting and filtering? |
This is a quick proof-of-concept patch for the idea of allowing the
render function to take full control of rendering content within a cell.
Instead of returning HTML for DataTables to add to the cell, the render
function updates the DOM directly and returns null to indicate that
touching the innerHTML is unnecessary.
This allows the view rendering code to retain references to actual dom
elements on the page for event handling and UI binding.
As an example, my application is using a Backbone Marionette view for
each cell's contents, binding the view to the td created by DataTables
and then rendering to it directly.
I first tried using column.createdCell, which gives convenient access to
the cell node, but that the initial drawing; subsequent re-displays only
call data and/or display and then overwrite the innerHTML, orphaning the
previous elements.
I don't really expect this patch to be accepted directly but I wanted to
open discussion about providing some method to accomplish direct
rendering control.
Issues to considering
Right now, I have to dig out of the meta parameter:
meta.settings.aoData[meta.row].anCells[meta.col]
but it could be passed as a parameter, or perhaps added as e.g.
meta.node. Alternatively, the render function could be permitted to
create and return the node itself.
rendering and that DataTables should not modify innerHTML
Using "null" is kinda dirty. Could be signaled by return type
(HTMLElement) or by using a different function than column.render which
always handles rendering