0

How can I wait until my find method has finished loading the model from the backend? After the model has loaded I want to fetch additional data and decorate my movie model with that data. The request to the external api from which the additional data is fetched is based upon properties of the movie model like year and title.

App.Movie.adapter = Ember.Adapter.create({
  find: function(record, objectId) {
    return Ember.$.ajax({
      headers: {
        'X-Parse-Application-Id': '',
        'X-Parse-REST-API-Key': ''
      },
      type: 'GET',
      url: 'https://api.parse.com/1/classes/Movie' + '/' + objectId
    }).then(function(data) {
      record.load(objectId, data);
    });
  }
});

App.MoviesMovieRoute = Ember.Route.extend({
  model: function (movie) {
    return App.Movie.find(movie.movie_id);
  },

  afterModel: function(movie, transition) {
    // currently undefined, undefined
    console.log(movie.get('title'), movie.get('year'));
  }
});

App.MoviesMovieController = Ember.ObjectController.extend({
  contentObserver: function () {
    // fetch additional data from external api
  }.observes('content')
});

Thank you

Kingpin2k
  • 47,277
  • 10
  • 78
  • 96
  • Try typing a print statement at the end of the method. That will show that the method has been done –  Nov 22 '13 at 19:23
  • How about running your ajax call as Async: false? it will have to get an answer before proceeding. – Moka Nov 22 '13 at 19:30

2 Answers2

0

For ember model, use fetch, it will return the promise, and ember will wait until resolving that model before doing the next model.

return App.Movie.fetch(movie.movie_id);

find builds up a dummy record and returns the record immediately (and populates it when the data is available), whereas fetch builds up the record, and a promise, and returns the promise, which resolves to the record when it's been populated.

They will both use the find method from the adapter.

App.MoviesMovieRoute = Ember.Route.extend({
  model: function (movie) {
    return App.Movie.find(movie.movie_id);
  },

  afterModel: function(movie, transition) {
    // currently undefined, undefined
    console.log(movie.get('title'), movie.get('year'));
  },

  serialize: function(model){
    return { movie_id: model.get('whateverfieldhastheid')};
  }
});
Kingpin2k
  • 47,277
  • 10
  • 78
  • 96
  • Is it possible to get the id from the dynamic url part? So the single view renders correctly after page/browser reload? And do I have to put the return statement in front of the ajax request for returning a promise or is it ok to leave off that return statement? Thx –  Nov 22 '13 at 20:28
  • The id and url part seems ok. But I'm getting this error message in the console: "Assertion failed: Cannot call get with 'id' on an undefined object." Any idea? –  Nov 22 '13 at 20:42
  • 1
    you need to implement the serialize hook in your route. I'll find an example for you. – Kingpin2k Nov 22 '13 at 21:00
  • Sorry... ;-) But now there is only a white screen. Nothing gets rendered and no error message in the console. Possible reason might be the single view is a subroute of the list view? Thx –  Nov 22 '13 at 21:22
  • It was rendering before? – Kingpin2k Nov 22 '13 at 22:41
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/41736/discussion-between-philipp-kosel-and-kingpin2k) –  Nov 22 '13 at 22:51
0

One way would be to implement find() with an RSVP Promise like so:

App.Movie = Ember.Object.extend({

});

App.Movie.reopenClass({
    find: function(objectId) {
        return Ember.RSVP.Promise(function(resolve, reject) {
            Ember.$.ajax({
                type: 'GET',
                url: 'https://api.parse.com/1/classes/Movie' + '/' + objectId
            }).success(function(data) {
                resolve(data);
            }).fail(function(data) {
                reject(data);
            })
        }
    }
});

Then, in your Route, you can add then to your promise:

App.MoviesMovieRoute = Ember.Route.extend({
    model: function (movie) {
        var movie = App.Movie.find(movie.movie_id); 
        movie.then(function() {
            // Gets called once the server returned loaded
            console.log(movie.get('title'), movie.get('year'));
        }, function() {
            // FailureHandler
        });
        return movie;
    },
});
  • Note that this isn't using EmberData at all. I don't know if that was a requirement?
Eaten by a grue
  • 391
  • 2
  • 5