Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to merge (aggregate) nested model collections in EmberJS?

Consider this model:

Grandparent
  parents: DS.hasMany('parent')

Parent:
  grandparent: DS.belongsTo('grandparent')
  children: DS.hasMany('child')

Child:
  parent: DS.belongsTo('parent')

I want to add a computed property children to Grandparent model, in which I expect a collection of Child models (Grandparent.children = merge each Grandparent.parents.children).

How to do that?

For this example data:

Grandparent { id: 0, parents: [0, 1] }

Parent { id: 0, grandparent: 0, children: [0] }
Parent { id: 1, grandparent: 0, children: [1,2] }

Child { id: 0, parent: 0 }
Child { id: 1, parent: 1 }
Child { id: 2, parent: 1 }

I want Grandparent.get('children') to return children with ids [0, 1, 2].

EDIT:

App.Grandparent.reopen({
  grandchildren: function(){
    var result = [];
    this.get('parents').forEach(function(parent) {
      parent.get('children').forEach(function(child){
        console.log('is this even called?');
        result.push(child);
      });
      console.log('coz this is!');
    });
    return result;
  }.property("parents", "[email protected]")
});

Why is the second loop empty? I know data is loaded (ember inspector).. so why is it not accesible here?

EDIT2:

Almost there! It seems the list was empty, becouse it was a promise array (which was not yet resolved), therefore at the time the code was executed - it was empty!

 grandchildren: function(){
    var grandchildren = [];
    this.get('parents').forEach(function(parent) {
      var promiseArray = parent.get('children');
      promiseArray.then(function() {
        promiseArray.forEach(function(child){
          grandchildren.push(child);
          console.log(child);
        });
      });
    });
    return grandchildren;
  }.property("parents", "[email protected]")

So this code correctly displays in console log all the grandchildren... but! it still does not return them. It's probably for the same reason - at the time the code hits return grandparent it's still empty. I'm thinking now, is there a way around that?

EDIT3:

It seems the root of the problem is the DS.hasMany('parent', { async: true }) and DS.hasMany('child', { async: true }). I've ommited the async part in the original question to make the model example more clear.

EDIT4:

I have solved my problems by removeing the async: true from the DS.hasMany and used this script to load them correctly without async.

This fixed the problem with "empty arrays" (unresolved promise arrays) and allowed me to access the properties. Then I did the following code (in the MODEL's reopen function):

grandchildren: function(){
  var res = Ember.ArrayProxy.create({content: Ember.A()});

  this.get('parents').forEach(function(parent){
    res.pushObjects(parent.get('children').toArray());
  });

  return res;
}.property('parents', '[email protected]')

And it works! Yay!

However, I'm still interested in the solution for ASYNC data

The next step is replaceing the fixtures with some data fetched from the server. And that data is asynchronous.. so I still need a solution with promises.

EDIT5: Test code:

grandchildren: function(){
  var res = Ember.ArrayProxy.create({content: Ember.A()});

  this.get('parents').forEach(function(parent) {
      var promiseArray = parent.get('children');
      promiseArray.then(function() {
        res.pushObjects(promiseArray.toArray());
      });
    });

  return res;
}.property('parents', '[email protected]')
like image 752
ioleo Avatar asked Nov 01 '22 06:11

ioleo


1 Answers

You may be looking for http://emberjs.com/api/classes/RSVP.html#method_all.

var promises = [];
this.get('parents').forEach(function(parent) {
  promises.push(parent.get('children'));
});
return Ember.RSVP.all(promises).then(function(results) {
  // return concatenated results
});

When you call grandchildren you will get a promise that resolves to the concatenated results.

In the future it looks like there will be support for hasMany through similar to rails. https://github.com/emberjs/data/issues/120

like image 157
varblob Avatar answered Nov 14 '22 11:11

varblob