Christoffer
Christoffer

Reputation: 514

Filter models by related model (hasMany)

I have a list of products with related tags. I want to filter the list to only show products that have the specified tag:

App.Product = DS.Model.extend({
    tags: DS.hasMany('Tag', { async: true }),
    name: DS.attr( 'string' )
});

App.Tag = DS.Model.extend({
    name: DS.attr('string')
});

App.ProductsTaggedRoute = Ember.Route.extend({
    model: function(params) {
        var store = this.store;

        return store.find('product').then(function() {
            store.filter('product', function(product, index, enumerable) {
                var match = false;

                product.get('tags').then(function(tags) {
                    tags.forEach(function(tag) {
                        if(tag.get('name') === 'Tag 1') {
                            console.log(product.get('name') + ' true');
                            match = true;
                        } else {
                            console.log(product.get('name') + ' false', tag.get('name'));
                        }
                    });
                });

                return match;
            });
        });
    }
});

App.Product.FIXTURES = [
    { id: 1, tags: [1,2,3], name: "test 1" },
    { id: 2, tags: [3], name: "test 2" },
    { id: 3, tags: [2,1], name: "test 3" },
    { id: 4, tags: [], name: "test 4" }
];

App.Tag.FIXTURES = [
    { id: 1, name: "Tag 1" },
    { id: 2, name: "Tag 2" },
    { id: 3, name: "Tag 3" },
    { id: 4, name: "Tag 4" }
];

The output is:

test 2 false undefined
test 3 false undefined
test 3 false undefined
test 1 true
test 1 false Tag 2
test 1 false Tag 3 

I don't understand why the first three are undefined? Also, I don't get any output in the template so it seems like the filter function isn't right:

{{#each controller}}
    {{ name }}
{{/each}}

Upvotes: 2

Views: 1106

Answers (1)

Kingpin2k
Kingpin2k

Reputation: 47367

You'll need to make sure the records are resolved before using the filter on it. This is a perfect use case for promises. You return a promise, and control what's resolved and when.

http://emberjs.jsbin.com/OxIDiVU/84/edit

model: function(params) {
    var store = this.store;

    return new Em.RSVP.Promise(function(resolve){
      //find products
      store.find('product').then(function(products) {
        // get all the tag promises
        var promiseArr = products.getEach('tags');
        //wait on them
        Em.RSVP.all(promiseArr).then(function() {

          var filter = store.filter('product', function(product, index, enumerable)   {
            var match = false;

            product.get('tags').forEach(function(tag) {
              if(tag.get('name') === 'Tag 1') {
                console.log(product.get('name') + ' true');
                match = true;
              } else {
                console.log(product.get('name') + ' false', tag.get('name'));
              }
            });

            return match;
          });  //filter

          resolve(filter);
       });  // RSVP All  
    });   //find
  });   // promise

 }

Upvotes: 2

Related Questions