8

I've been beating my head against this problem all day, and I feel like I'm close to a solution but just can't quite make it happen. I'm using Ember.js with Ember-Data and the Fixtures adapter, eventually migrating to a REST adapter. The basic problem is this: I have Sites and Supervisors, with a many-to-many relationship. I want to present the user with a select box for their existing site/supervisor pairings, sorted by site, ie:

  • Site 1 - Supervisor 1
  • Site 1 - Supervisor 2
  • Site 2 - Supervisor 1 (remember, many to many)
  • Site 2 - Supervisor 3

I need to wrangle these two resources into a single array that I can pass to a view which inherits (or will inherit) from Ember.Select. Currently I'm attempting this with a method on the Supervisors controller which I'm calling "flat", because it will return a flattened array representing these relationships. The controller is shown below. I'm using .find().then() to process the data after the promise has been fulfilled. The data that I get back appears to contain all four of my fixtures, but when I try any of the enumerable methods on them (notably forEach), it behaves as if it has only returned the first object. I have tried iterating over the data object as well as data.get('content'). I'm quite new to Ember, so maybe I'm going about this the wrong anyway, but regardless this seems very strange to me. Here's my code:

App.SupervisorsController = Ember.ArrayController.extend({
  flat: function(){
    return App.Supervisor.find().then(function(data){
      var c = data.get('content') ;
      console.log(c) ;    // <-- logs an object containing four records,
                          //     with attribute "length" showing 4
                          //     Great! (see below for log output)

      console.log(c[0]) ; // <-- logs first record. Great!
      console.log(c[1]) ; // <-- undefined (?!)
      console.log(c[2]) ; // <-- undefined (?!)
      console.log(c[3]) ; // <-- undefined (?!)
      console.log(c.get('length')) ; // <-- 1 (not four?!)

      return c ; // <-- eventually this will return the newly constructed array
    }) ;
  }
}) ;

And here's the log output from the first console.log() call

0: Object
1: Object
2: Object
3: Object
__ember1376005434256: "ember325"
__ember1376005434256_meta: Meta
_super: undefined
length: 4
__proto__: Array[0]

Can you tell me what I'm missing here? I can't figure out how to access each of the four resulting supervisors.

Thanks!

Ben
  • 571
  • 2
  • 4
  • 15

1 Answers1

9

It appears like you're accessing the models before they are finished loading (You can see this in the property, isUpdating). If you feel like lazily looking at this you can use ember run later to just see the items a wee bit later. Or you can set the model on the controller and render it and let ember update the view when the models are finished loading...

 Ember.run.later(function(){
    data.forEach(function(item){
    console.log(item);
   });
 }, 2000);



 App.ApplicationRoute = Ember.Route.extend({
   activate: function(){
     this.controllerFor('supervisors').set("model", App.Supervisor.find());
   }
 });

http://jsbin.com/ijiqeq/12/edit

Good luck with Ember!

 someArray: function(){
   var arr = Ember.A();
   this.get('model').forEach(function(item){
     item.get('sites').forEach(function(site){
       arr.pushObject(someObject); //some object that is represents each specific combination
     });
   });
 }.property('model')
Kingpin2k
  • 47,277
  • 10
  • 78
  • 96
  • Sorry, I missed that in the first post, Can you generate a jsbin/jsfiddle showing the error? – Kingpin2k Aug 09 '13 at 14:27
  • Thanks for taking a look at this, Daniel. I put it in a jsbin: http://jsbin.com/ijiqeq/3/edit. Running it in the bin shows that the data object has four items, but _all_ of the items are showing null when I iterate over them, which is strange and makes me think that somehow the first item was getting set elsewhere in my code. Not sure how that could happen. So I am a little more confused now... – Ben Aug 12 '13 at 22:22
  • just to clarify - the items are showing `undefined`, not `null` – Ben Aug 12 '13 at 22:30
  • I've updated the jsbin with a working view, and hopefully explained it a bit. It's all about timing, those models aren't materialized right away after the then, just the shells of the models which Ember can hook into and monitor. – Kingpin2k Aug 13 '13 at 05:52
  • Thanks @Daniel. I follow what you've done here, and it makes sense. My problem is that I would like to alter the structure of that array, and I'm not sure where/how to do it. Right now, Supervisors.find() gives me an array with each supervisor, and each one has an attribute "sites", which is an array of the site IDs to which the sup belongs. I want to flatten that array so that each site/supervisor combination is an element in the array. That array will then be bound to my Ember.Select element. I'm just not sure where to process that array or how to set up an observer for that kind of change. – Ben Aug 13 '13 at 22:33
  • I ran out of room on that last comment, but am I making sense? Or am I going about this all wrong? Thanks for sticking with me on this one. – Ben Aug 13 '13 at 22:37
  • 1
    hmmmm, I think I understand, so you kind of want a left join (duplicating a supervisor for each site). So I would recommend against this, just because then you have more than one source of truth for a supervisor. Aka, if you change something on a supervisor model, you'd have to hunt down the rest of the supervisor model's that should be the same model and update them. Can you give me an example of why you'd like the model's duplicated, and maybe I can give an example of a workaround to give you the same results. – Kingpin2k Aug 14 '13 at 02:49
  • That's exactly right. I want the user to be able to select a site/supervisor combination on a form using a single ` – Ben Aug 14 '13 at 15:28
  • 1
    I would generate an additional array depending on the model. I'll put it above. – Kingpin2k Aug 18 '13 at 23:53