Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you pre-load related data such that your relationships are cached in ember-data?

I have a simple hasMany/belongsTo relationship that looks like this

App.Foo = DS.Model.extend({
  bar: belongsTo('bar', { async: true})
});
App.Bar = DS.Model.extend({
  foos: hasMany('foo', { async: true})
});

I have situations in my route code that fire off a request and when the response comes back I access the related "bar" model as I filter down / etc

this.store.all('foo').clear();
var fooz = self.store.all('foo'); //new code
return this.store.find('foo').then(function(response) {
  var filtered = response.filter(function(foo) {
    return foo.get('bar').get('name') === 'bazz';
  });
  //other code that would normally be executed top-down
  //including side-effect stuff like this
  //self.store.createRecord('foo', someHash);
  return fooz; //new code
});

The above doesn't work the first time around as foo.get('bar') is a promise. But this is only a problem the first time through (subsequent $.ajax requests seems to have all the bar objects cached so it's a non issue)

What's strange is that before I even boot the app I've already pulled down all the bar data in the init (shown below). So why does ember-data even need to resolve the promise for "bar" when technically that data should already be in the store locally?

App.initializer({
  name: 'bootstrap',
  initialize: function() {
    App.deferReadiness();
    var store = App.__container__.lookup("store:main");
    var bars = store.find('bar');
    var configurations = store.find('configuration');
    Ember.RSVP.all([bars, configurations]).then(results) {
      App.advanceReadiness();
    });
  }
});
like image 333
Toran Billups Avatar asked Jan 05 '14 13:01

Toran Billups


People also ask

What is Ember data store?

Ember Data: A Comprehensive Tutorial for the ember-data Library. Ember Data is a library for robustly managing model data in Ember. js applications. Ember Data provides a more flexible and streamlined development workflow, minimizing code churn in response to what would otherwise be high impact changes.

How do I use Ember data?

Ember comes with a data management library called Ember Data to help deal with persistent application data. Ember Data requires you to define the structure of the data you wish to provide to your application by extending DS. Model . import DS from 'ember-data'; export default DS.


1 Answers

Let's separate a few things here

Store cache

this.store.all('foo').clear();

just breaks the internal all filter until a foo record is modified/added/removed forcing the filter to recalculate for the record in the store. I say this to show that clear isn't removing the records from ED's store.

Example (click the button, watch the console, read the fun action code)

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

That being said it isn't the ajax that's being cached, it's the property/relationship on the record instance that's being cached (and the record).

The proper way to remove the records of a type from the store is store.unloadAll('foo')

Promiselandia

I know you're already familiar with promises, so this part may be worthless, but, worth documenting

The async relationships are really cool because they return PromiseObject/PromiseArray for belongsTo/hasMany. The PromiseObject/PromiseArray extend ObjectProxy/ArrayProxy (these are the same things that ObjectController/ArrayController extend). This essentially gives the PromiseObject/PromiseArray the ability to proxy getting/setting of properties to the model underneath. In this case the setting/getting happens on the promise doesn't "work" until the promise has been resolved (it won't crash, just return undefined). *Caveat, methods don't exist on the promise, so you can't call save on the promise and expect it to work.

Ex. using your models.

var foo = this.store.find('foo', 1);

var bar = foo.get('bar');  // PromiseObject

bar.get('name'); // undefined

later, bar has resolved, bar is still the PromiseObject

bar.get('name'); // billy

foo will keep returning the PromiseObject

var bar2 = foo.get('bar');  // PromiseObject

bar2.get('name'); // billy

saving

bar.save(); // Boom no workey

bar.then(function(realBar){
  realBar.save(); // workey
});

In your case I have 3 recommendations

Build your own promise, resolve when you want, use Ember.RSVP.all on the records needed (respecting that they may or may not be resolved yet, hence async)

var self = this;

var promise = new Ember.RSVP.Promise(function(resolve, reject){
  self.store.find('foo').then(function(foos) {
    Em.RSVP.all(foos.getEach('bar')).then(function(bars){

      var filtered = bars.filterBy('name', 'bazz');

      resolve(filtered);
    });
  });
});
return promise;

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

async properties

A lot of times with async objects/properties that aren't resolved during the model hook (which blocks on promises and wait's until they are resolved) a good trick is to set a placeholder object etc.

var items = [];

controller.set('model', items);

// promise from above
promise.then(function(records){
  items.pushObjects(records.toArray()); // toArray may or may not apply
});

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

like image 134
Kingpin2k Avatar answered Sep 22 '22 12:09

Kingpin2k