Calling jQuery plugin with EmberJS creates race conditions
I am using jQuery DataTables plugin to render data in Ember. I'm running into classic race problems and some of my understanding of Ember and the Ember Run-loop must be incomplete. Here's what's going on.
- I have dumped data table into my template using
<table>...<tbody>{{#each user in model}}...
- In my view, I call the DataTables library in a method
didInsertElement
and terminate it inEmber.run.scheduleOnce('afterRender', function() { $('#myTable').DataTable(); })
- The first time I access this page code, I get the following error:
Uncaught Error: Cannot perform operations on a Metamorph that is not in the DOM.
- If I access it again, it works fine.
I looked at similar StackOverflow posts:
- Ember.js - "Unable to perform operations on metamorphic that is not in DOM" triggered by template
- ember js with datatables plugin
But these fixes don't seem to work. I suspect DataTables is trying to update the DOM before Ember has finished rendering it, but why isn't my address Ember.run.scheduleOnce('afterRender', ...)
called?
Strange, I can get it to work by doing the following:
Old (race condition) Code in view:
didInsertElement: function() {
Ember.run.scheduleOnce('afterRender', function() {
$('#orgUsers').DataTable();
});
}
New working code in view:
didInsertElement: function() {
setTimeout(function() {
$('#orgUsers').DataTable();
}, 0);
}
Note that I have specified a javascript delay of setTimeout
0 seconds! But it works every time.
Can anyone please help me understand (1) why wrapping this in setTimeout()
solves all my problems, (2) what is the "Horrible way" to deal with this? Thank!
source to share
I expect this to work:
Ember.run.next(this, function() {
Ember.$('#orgUsers').DataTable();
});
This is preferred over your code setTimeout
. Ember will schedule your function for the next loop. didInsertElement
called from a task in the queue render
. Your call scheduleOnce
goes to a queue afterRender
that is "descending" from the queue render
, but in the same loop iteration.
Usage will run.next
schedule the task in a new startup cycle, so there will be no life cycle issues in the current cycle.
source to share