3
votes

I'm using the jQuery DataTables plugin to render data in Ember. I'm running into classic race condition issues and some part of my understanding of Ember and the Ember run-loop must be incomplete. Here's what's happening.

  • I output a table of data in my Template, using <table>...<tbody>{{#each user in model}}...
  • In my View, I call the DataTables library in the didInsertElement method, and wrap it in Ember.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 have looked at similar StackOverflow posts on this:

But these fixes don't seem to work. I suspect that DataTables is trying to update the DOM before Ember has finished rendering it, but then why doesn't my called Ember.run.scheduleOnce('afterRender', ...) address that?

Strangely, I can get it 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 setTimeout delay of 0 seconds! But this works every time.

Can someone help me understand (1) why does wrapping this in setTimeout() solve all my problems, (2) what is the "Ember Way" to handle this? Thanks!

1
Data tables is meant for a static table, and not suitable for Ember/Handlebars. The moment the data changes and Ember attempts to manipulate the view you will run in to trouble.Kingpin2k
kingpin2k makes a good point- I'm not familiar with DataTable, but it makes sense. I have found that Ember is powerful enough to let me do lots of things I used to use libraries for... I roll my own tables, personally.Steve H.
Yeah, I'm starting to come around to that way of thinking. It seems crazy that tables with filter/sort/pagination aren't available out of the box in Ember, but it's also not too hard to roll your own. Thx for the all the input, guys.Josh Padnick
@JoshPadnick: I'm literally in the exact same situation. Down to the T. What did you end up doing? I'm 2 hours in searching for a solution, but can't find anything relevant online except this SO question. Thanks!sergserg
@Ashok.N See discuss.emberjs.com/t/… for some guidelines on how I did it. Unfortunately, I don't have the time to package up the code and clean out our app-specific items.Josh Padnick

1 Answers

2
votes

I would expect this to work:

Ember.run.next(this, function() {
    Ember.$('#orgUsers').DataTable();
});

This is preferable to your setTimeout code. Ember will schedule your function for the next run loop. didInsertElement is called from a task in the render queue. Your call to scheduleOnce goes into the afterRender queue, which is "downstream" from the render queue, but in the same loop iteration.

Using run.next will schedule the task in a new run loop, so there won't be lifecycle issues in the current loop.