How to deal with async properties in Ember when I need blocking calls?

478 views Asked by At

We were using a model with a hasMany with embedded children. This was fine so that whenever I called model.get('children') everything just worked.

We've now changed that children property to async:true, and I can't seem to find proper documentation on how you should handle this.

Let me give you an example. I'll use simplified json to represent my Ember setup, just for the sake of simplicity.

Say I have a Model like this:

model:{
 hasMany: {children: {async: true} },
 isActive: boolean
}

Say I have a Template like this:

{{#if lastChildIsActive}}
  <p>I'm the last one!</p>
{{/if}}

And I have a Controller:

controller:{
 lastChildIsActive: function(){
  return this.get('model').get('children').get('lastObject').get('isActive')
 }
}

Ok, so with this setup when async: false was being used, everything just worked.

But now, with async true, that call in the controller for .get('children') SOMETIMES just doesn't return anything, because it's async I guess.

Now I could use promises, and refactor my controller to this:

controller:{
 lastChildIsActive: function(){
  this.get('model').get('children').then(function(children){

    return children.get('lastObject').get('isActive');

  });
 }
}

The problem with the second refactor is, I'm not longer returning the isActive value, I'm now returning the promise object.

But the template doesn't want a promise, it needs the returning value.

SO, how can I make sure the async has loaded, while being able to return the actual result of the call instead of the promise?

2

There are 2 answers

0
AudioBubble On BEST ANSWER

By using a view and didInsertElement, you can get the children of the parent and then update the attribute on the controller, which will appear in your template.

App.IndexView = Ember.View.extend({
  didInsertElement: function() {
    controller = this.get('controller');
    controller.get('model').get('children').then(function(children){
      active = children.get('lastObject').get('active');
      controller.set('lastChildIsActive', active);
    });
  }
});

See this fiddle: http://jsfiddle.net/f9DAc/2/

1
M.G.Manikandan On

You have to use observer to listen for the changes in children. Refer the change I have made in lastChildIsActive method below. As children is an array type, I am listening for "children.@each". Whenever, there is a change in "childern", lastChildIsActive will be updated automatically.

controller:{
 lastChildIsActive: function(){
  return this.get('model').get('children').get('lastObject').get('isActive')
 }.property('children.@each')
}