title: Ember: Fetching data for objects that depend on each other
body: <p>I'm trying to build a front-end for a metrics tool with Ember. The code that I've written so far has been very much influenced by Eviltrout's emberreddit application</p>
  
  <p><a href="https://github.com/eviltrout/emberreddit" rel="nofollow">https://github.com/eviltrout/emberreddit</a></p>
  
  <p>The goal is to have two classes that depend on each other: metrics and filters. </p>
  
  <p>1) Once the application initializes, the filters, which are instances of the Filter-class, are loaded from the server. Once the filters have loaded, they are displayed as checkboxes on the screen. After that, the metrics objects should take the filters as parameters and query the server for data. </p>
  
  <p>2) Once the user changes the checkboxes and thus updates the filter objects, the application should take the filters as parameters again and fetch new metrics data from the server. </p>
  
  <p>My problem is that I don't know how to handle the dependencies between these two sets of objects with asynchronous ajax calls. At it's current state, my application doesn't finish loading the filters when it already starts loading the metrics. Therefore, the filters don't get passed as parameters for the metrics ajax-call.</p>
  
  <p>My question is: What's the best way to do this ember? There surely has to be a way to handle the order of ajax calls. My intuition is that manually adding observers isn't the way to go.</p>
  
  <p><strong>Here are the models of my application:</strong></p>
  
  <pre><code>//FILTER MODELS
  
  var defaultFilters = ['dates', 'devices'];
  
  //set Filter class. The Filter object will be multiplied for each filter.
  App.Filter = Ember.Object.extend({
  
      //capitalize first letter to get title
      filterTitle: function() {
          return this.get('id').charAt(0).toUpperCase() + this.get('id').slice(1);
      }.property('id'),
  
      //set attribute to see if filter has loaded
      loadedFilter: false,
  
      //create method to load filter values from server
      loadValues: function() {
          var filter = this;
          return Ember.Deferred.promise(function (p) {  
              if (filter.get('loadedFilter')) { 
                  p.resolve(filter.get('values'));
              } else {
                  p.resolve($.getJSON("http://127.0.0.1:13373/options/" + filter.get('id')).then(function(response) {
                  var values = Ember.A();
                  response[filter.get('id')].forEach(function(value) {
                      values.push(value);
                  });
                  filter.setProperties({values: values, loadedFilter: true});
                  return values;
                  }))
              }})}
      }  
  );
  
  
  
  //reopen class to create "all" method which returns all instances of Filter class
  App.Filter.reopenClass({
      all: function() {
          if (this._all) {return this._all; }
          var all = Ember.A();
          defaultFilters.forEach(function(id) {
              all.pushObject(App.Filter.create({id: id}));
          });
          this._all = all;
          return all;
  }});
  
  //Create a Filters array to store all the filters.
  App.Filters = App.Filter.all();
  
  //METRIC MODELS
  App.Metric = Ember.Object.extend({
  
      metricTitle: function() {
          return this.get('id').charAt(0).toUpperCase() + this.get('id').slice(1);
      }.property('id'),
  
      loadedMetric: false,
  
      filtersBinding: 'App.Filters',
  
      loadValues: function() {
      var metric = this;
      var filters = metric.get('filters');
      if (filters.get('loadedFilters'))
      console.log('loading metrics'); 
      return Ember.Deferred.promise(function (p) {  
          if (metric.get('loadedMetric')) { 
              p.resolve(metric.get('values'));
  
          } else {
              p.resolve(
                  console.log('sending ajax'),
                  $.ajax({ 
                  url: "http://127.0.0.1:13373/" + metric.get('id') + "/",
                  data: JSON.stringify(metric.get('filters')),
                  }).then(function(response) {
              var values = Ember.A();
              response[metric.get('id')].forEach(function(value) {
                  values.push(value);
              });
              metric.setProperties({"values": values, "loadedMetric": true});
              return values;
              }))
          }})}
  
  
  });
  
  App.Metric.reopenClass({
  
  
      findByView: function(searchView) {
          if (this._metrics) {return this._metrics; }
          var metrics = Ember.A();
          defaultMetricsSettings.forEach(function(metric) {
              if (metric.view == searchView)
                  metrics.pushObject(App.Metric.create({id: metric.id},{view: metric.view}, {calculation: metric.calculation}, {format: metric.format}, {width: metric.width}));
          });
          this._metrics = metrics;
          return metrics;
      }
  });
  </code></pre>
  
  <p><strong>And here are the routes:</strong></p>
  
  <pre><code>App.ApplicationRoute = Ember.Route.extend({
      //set application routes model to all filters
      model: function() {
          return App.Filter.all();
      },
  
      //after filter has loaded, let's load its values
      afterModel: function(model) {
          return model.forEach(function(item) {
              item.loadValues();
          });
      },
  
      //create a controller called ApplicationController and pass the filter as its model
      setupController: function(controller, filter) {
          controller.set('model', filter);
      }
  
  });
  
  App.DashboardRoute = Ember.Route.extend({
      model: function() {
          return App.Metric.findByView('Dashboard');
      },
  
      afterModel: function(model) {
          return model.forEach(function(item) {
              item.loadValues();
          });
      },
  
      setupController: function(controller, metric) {
          controller.set('model', metric);
      }
  });
  </code></pre>
  
  <p><strong>Controllers:</strong></p>
  
  <pre><code>App.ApplicationController = Ember.ArrayController.extend({
      //ApplicationController controls all the filters. Let's create a controller to handle each instance of a filter
      itemController: 'filter'
  });
  
  App.FilterController = Ember.ObjectController.extend({
      //this sets the titleId property that is used only for binding html attributes in template. Stupid way to do this.
      titleId: function() {
          return "#" + this.get('filterTitle');}.property('filterTitle')
  });
  </code></pre>