Rushi
Rushi

Reputation: 1662

Ember.js - Managing Asynchronous Events & Callbacks

I'm not using Ember Data, and have an ajax call in my Model to pull data from a remote source. After I've successfully received the data from the API, I want to sort/filter it based on category. My plan is that once I get the data from the Model, I can manage the filtered state of the data through the controller.

My problem is that because fetching the data in the Model is asynchronous, i can't exactly call a method in my controller to filter/sort the data to be displayed in the template.

The relevant pieces of my code, below and in my jsfiddle. In my template iterating over issue_list I can easily display the information. However, I would like to iterate over the categorized_issues Array ... and I dont know when issue_list array really gets set so I can call the categorize method of the IssuesController.

// Default Route for /issues
App.IssuesIndexRoute = Ember.Route.extend({
    setupController: function() {
        var issues = App.Issue.all(25);
        this.controllerFor('issues').processIssues(issues);
    }
});

// Model
App.Issue = Ember.Object.extend({});
App.Issue.reopenClass({
    // Fetch all issues from the ajax endpoint. 
    // Won't work on the JS fiddle
    all: function() {                
        var issues = [];
        $.ajax({
            url: "http://localhost:3000/issues.json",
            dataType: 'json',
        }).then(function(response) {
            response.issues.forEach(function(issue) {           
                issues.addObject(App.Issue.create(issue));
            }, this);
        });

        return issues;
    },
});

// Controller
App.IssuesController = Ember.ArrayController.extend({
    issue_list: [],
    categorized_issues : {"open":[], "closed": []},

    processIssues: function(issues) {
        this.set('issue_list', issues);
        return issues;
    },

    categorize: function() {
        var self = this;
        this.issue_list.forEach(function(i) {
            // Based on the issue open or closed status
            if (i.status == "open") {
                self.categorized_issues["open"].addObject(i);
            } else {
                self.categorized_issues["closed"].addObject(i);
            }
        });
    },
});

So my plan is:

  1. Fetch Data from Model
  2. Re-categorize the data based on it's status (open or closed) in the controller.
  3. Display this new data in the template.

I can seem to achieve this. Any ideas on how to go about it ?

DEBUG: ------------------------------- 
DEBUG: Ember.VERSION : 1.0.0-rc.2
DEBUG: Handlebars.VERSION : 1.0.0-rc.3
DEBUG: jQuery.VERSION : 1.9.1
DEBUG: ------------------------------- 

Upvotes: 2

Views: 1703

Answers (1)

mavilein
mavilein

Reputation: 11668

An easy solution would be to declare categorize() as an observer:

App.IssuesController = Ember.ArrayController.extend({
    issue_list: [],
    categorized_issues : {"open":[], "closed": []},

    processIssues: function(issues) {
        this.set('issue_list', issues);
        return issues;
    },

    categorize: function() {
        var self = this;
        // clear the arrays to avoid redundant objects in the arrays
        self.get("categorized_issues.open").clear();
        self.get("categorized_issues.closed").clear();

        this.issue_list.forEach(function(i) {
            // Based on the issue open or closed status
            if (i.status == "open") {
                self.get("categorized_issues.open").addObject(i);
            } else {
                self.get("categorized_issues.closed").addObject(i);
            }
        });
    }.observes("issue_list.@each"),
});

This would mean that the observer would get triggered on each change of the array. This would be likely no performance problem in most cases. To ensure that categorize is just run once, it would be even better, if you use Ember.run.once:

App.IssuesController = Ember.ArrayController.extend({
    issue_list: [],
    categorized_issues : {"open":[], "closed": []},

    processIssues: function(issues) {
        this.set('issue_list', issues);
        return issues;
    },
    issueListObserver : function(){
        Ember.run.once(this, this.categorize);
    }.observes('issue_list.@each'),

    categorize: function() {
        var self = this;
        // clear the arrays to avoid redundant objects in the arrays
        self.get("categorized_issues.open").clear();
        self.get("categorized_issues.closed").clear();

        this.issue_list.forEach(function(i) {
            // Based on the issue open or closed status
            if (i.status == "open") {
                self.get("categorized_issues.open").addObject(i);
            } else {
                self.get("categorized_issues.closed").addObject(i);
            }
        });
    }
});

Upvotes: 5

Related Questions