Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AJAX promise without Ember Data

I have decided to not use ember-data as it's not production ready and still changing. My app only needs to make a few ajax requests anyway so it shouldn't make too big of a difference. I am having trouble understanding how to handle an ajax promise response.

When my user loads the app they already have an authenticated session. I am trying to ping the server for that users info and display it in my template. It seems my template is rendered before my ajax request returns results and then does not update with the promise.

// route
App.ApplicationRoute = Ember.Route.extend({
    setupController: function(){
        this.set("currentUser", App.User.getCurrentUser());
    }
});


// model
App.User = Ember.Object.extend({
    email_address: '',
    name_first: '',
    name_last: '',
    name_full: function() {
        return this.get('name_first') + ' ' + this.get('name_last');
    }.property('name_first', 'name_last')
});
App.User.reopenClass({
    getCurrentUser: function() {
        return $.ajax({
            url: "/api/get_current_user",
            type: "POST",
            data: JSON.stringify({})
        }).then(function(response) {
            return response;
        });
    }
});

In my template:

<h1> Hey, {{App.currentUser.name_first}}</h1>

How would I update the template when I receive a response or delay rendering until I have a response?

like image 842
user1168427 Avatar asked Mar 25 '13 05:03

user1168427


2 Answers

Actually the answer is quite easy: You do not need to use a promise. Instead just return an empty object. Your code could look like this:

App.User.reopenClass({
    getCurrentUser: function() {
        var user = App.User.create({}); //create an empty object
        $.ajax({
            url: "/api/get_current_user",
            type: "POST",
            data: JSON.stringify({})
        }).then(function(response) {
            user.setProperties(response); //fill the object with your JSON response
        });
        return user;
    }
});

What is happening here?

  1. You create an empty object.
  2. You make an asynchronous call to your API...
  3. ... and in your success callback you fill your empty object.
  4. You return your user object.

Note: What is really happening? The flow mentioned above is not the sequence in which those actions are happening. In reality the points 1,2 and 4 are performed first. Then some time later, when the response returns from your server, 3 is executed. So the real flow of actions is: 1 -> 2 -> 4 -> 3.

So the general rule is to always return an object that enables Ember to do its logic. No values will be displayed first in your case and once your object is filled Ember will start do its magic and auto update your templates. No hard work needs to be done on your side!


Going beyond the initial question: How would one do this with an array? Following this general rule, you would return an empty array. Here a little example, which assumes, that you might like to get all users from your backend:

App.User.reopenClass({
    getAllUsers: function() {
        var users = []; //create an empty array
        $.ajax({
            url: "/api/get_users",
        }).then(function(response) {
            response.forEach(function(user){
                var model = App.User.create(user); 
                users.addObject(model); //fill your array step by step
            });
        });
        return users;
    }
});
like image 160
mavilein Avatar answered Nov 15 '22 01:11

mavilein


I'd use Ember.Deferred instead of returning an empty array as mentioned before.

App.User.reopenClass({
  getAllUsers: function() {
    var dfd = Ember.Deferred.create();
    var users = [];

    $.ajax({
        url: "/api/get_users",
    }).then(function(response) {
        response.forEach(function(user){
            var model = App.User.create(user); 
            users.addObject(model);
        });
        dfd.resolve(users);
    });
    return dfd;
  }
});

In your model hook all you have to do is this

model: function(){
  return App.User.getAllUsers();
}

Ember is smart enought and knows how to handle the promise you return, once it's resolved the model will be correctly set, you can also return a jQuery promise but it will give you some weird behavior.

like image 6
Daniel Guerra Avatar answered Nov 14 '22 23:11

Daniel Guerra