Issue with Ember Model promises

876 views Asked by At

I'm trying to do some basic stuff with Ember Model but I'm experiencing some weird behaviors with promises. Not sure I understand very well how it's supposed to work.

So, I have this route:

App.ProfilesIndexRoute = Ember.Route.extend {

  redirect: ->
    App.Profile.fetch().then (profiles) ->
      console.log profiles.get('length')
      @transitionTo 'profile', profiles.get('firstObject')

}

I simply want people to be redirected to /profiles/123 (= the first profile) when they access /profiles.

Here is the Profile adapter:

App.Profile.adapter = Ember.Adapter.create {

  findAll: (klass, records) ->
    $.ajax('/api/users/' + $.cookie('user_id'), {
      type: 'get'
      headers: {
        'Content-Type': 'application/json'
        'Authentication-Token': $.cookie('token')
      }
      dataType: 'json'
    }).then (res) ->
      profiles = []
      // some stuff done here
      records.load klass, profiles

}

When I go to /profiles, here is what I see in my console:

0
Transitioned into 'profiles.index'
XHR finished loading: "http://localhost/api/users/456". 

0 is the result of console.log profiles.get('length'). It seems that it's called before the AJAX call had the chance to finish. What I should have in my console is something like this:

Transitioned into 'profiles.index'
XHR finished loading: "http://localhost/api/users/456". 
5

What am I doing wrong here? Someone here suggested me to use fetch instead of find but it doesn't seem to solve my problem because things are not executed in the right order.

Thank you!

3

There are 3 answers

0
Vinch On BEST ANSWER

I finally found how to solve the problem thanks to this jsFiddle by Erik Bryn.

I was missing a return here:

App.Profile.adapter = Ember.Adapter.create {

  findAll: (klass, records) ->
    $.ajax('/api/users/' + $.cookie('user_id'), {
      type: 'get'
      headers: {
        'Content-Type': 'application/json'
        'Authentication-Token': $.cookie('token')
      }
      dataType: 'json'
    }).then (res) ->
      profiles = []
      // some stuff done here
      records.load klass, profiles
      return records // HERE

}

Also, I now use the init method in my ProfilesIndexRoute instead of redirect:

App.ProfilesIndexRoute = Ember.Route.extend {

  init: ->
    App.Profile.fetch().then (profiles) =>
      @transitionTo 'profile', profiles.get('firstObject')

}
0
Marcio Junior On

I think that the way you are overring the adapter is wrong:

You are using the jquery ajax deferred. But I think that you need to wrap that call in RSVP. Because ember use the RSVP to handle promisses.

Give a look in that implementation

App.Profile.adapter = Ember.Adapter.create({
    ajaxSettings: function(url, method) {
        return {
            headers: {
                'Content-Type': 'application/json'
                'Authentication-Token': $.cookie('token')
            },
            dataType: "json"
        };
    },
    findAll: function(klass, records) {
        var url = '/api/users/' + $.cookie('user_id'),
        self = this;

        return this.ajax(url).then(function(data) {
            self.didFindAll(klass, records, data);
            return records;
        });
    }   
});

I used the findAll implementation from RESTAdapter and just changed the url, to match what you want.

But if your response return just one object, I think that find method is better:

...
find: function(record, id) {
    var url = '/api/users/' + $.cookie('user_id'),
        self = this;

    return this.ajax(url).then(function(data) {
      self.didFind(record, id, data);
      return record;
    });
},
...
0
intuitivepixel On

You should redirect to a different route from the afterModel hook:

App.ProfilesIndexRoute = Ember.Route.extend {

  model: ->
    App.Profile.fetch()

  afterModel: (profiles, transition) =>
    @transitionTo 'profile', profiles.get('firstObject')

}

Furthermore since you are using @ you should use the fat arrow => to have the correct reference to this.

Hope it helps.