Ember.js - 管理异步事件&回调

时间:2013-03-31 17:27:16

标签: javascript ember.js

我没有使用Ember Data,并且在我的模型中有一个ajax调用来从远程源提取数据。在我成功从API接收数据后,我想根据类别对其进行排序/过滤。我的计划是,一旦从模型中获取数据,我就可以通过控制器管理数据的过滤状态。

我的问题是因为获取模型中的数据是异步的,我无法在控制器中调用一个方法来过滤/排序要在模板中显示的数据。

我的代码的相关部分,位于my jsfiddle下方和{{3}}。在我的模板迭代issue_list我可以轻松地显示信息。但是,我想迭代categorized_issues数组...我不知道issue_list数组确实何时被设置,所以我可以调用categorize方法问题控制器。

// 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);
            }
        });
    },
});

所以我的计划是:

  1. 从模型中获取数据
  2. 根据数据在控制器中的状态(打开或关闭)重新分类数据。
  3. 在模板中显示此新数据。
  4. 我似乎可以做到这一点。关于如何去做的任何想法?

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

1 个答案:

答案 0 :(得分:5)

一个简单的解决方案是声明categorize()作为观察员

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"),
});

这意味着观察者会在每次更改数组时触发。在大多数情况下,这可能不会出现性能问题。要确保categorize只运行一次,如果使用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);
            }
        });
    }
});