Emberjs控制器初始化

时间:2013-07-01 20:06:37

标签: ember.js

我正在玩emberjs几天,并认为我理解基础知识。现在我正在尝试构建一个真实的应用程序,并且已经遇到了一个奇怪的问题。

我想要一个使用'view'帮助器的应用程序模板来包含其他一些视图。我还想要一些“全局”模型,其中包含我希望能够在不同视图中使用的有关环境的信息(例如登录的用户帐户信息等)。

我试过这个:http://jsfiddle.net/UzgMd/7/

<script type="text/x-handlebars" data-template-name="header">
    <div>Header {{fullName}}</div>
</script>

<script type="text/x-handlebars" data-template-name="sidebar">
    <div>Sidebar</div>
</script>

<script type="text/x-handlebars" data-template-name="application">
    <div>{{view App.HeaderView}}</div>
    <div>{{view App.SidebarView}}</div>
</script>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="https://raw.github.com/wycats/handlebars.js/1.0.0-rc.3/dist/handlebars.js"></script>
<script type="text/javascript" src="https://raw.github.com/emberjs/ember.js/release-builds/ember-1.0.0-rc.2.js"></script>
<script type="text/javascript" src="https://raw.github.com/MilkyWayJoe/cdnjs/master/ajax/libs/ember-data.js/0.12.00-latest20130328/ember-data-latest.js"></script>

使用以下JS:

App = Ember.Application.create();

App.Store = DS.Store.extend({
    revision: 12,
    adapter: 'DS.FixtureAdapter'
});
App.AccountInfo = DS.Model.extend({

    firstName: DS.attr('string'),
    lastName: DS.attr('string'),

    fullName: function() {
        return this.get('firstName') + ' ' + this.get('lastName');
    }.property('firstName', 'lastName')
});

App.AccountInfo.FIXTURES = [{
    id: 1,
    firstName: "John",
    lastName: "Doe"
}];

//App.headerController = Ember.ObjectController.extend({}).create(); // works
App.HeaderController = Ember.ObjectController.extend({}); // doesnt work

App.HeaderView = Ember.View.extend({
    templateName: 'header',

    //controller: App.headerController // works
    controller: App.HeaderController.create() // doesnt work
});
App.SidebarView = Ember.View.extend({
    templateName: 'sidebar'
});

App.ApplicationController = Ember.Controller.extend({});
App.ApplicationRoute = Ember.Route.extend({

    model: function() {
        return App.AccountInfo.find(1);
    },

    setupController: function(controller, model) {
        this._super(controller, model);

        //App.headerController.set('model', model); // works
        this.controllerFor('header').set('content', model); // doesnt work

    }

});

但它不起作用,因为第47行中的controllerFor() - 方法返回HeaderController的新实例而不是第30行中已创建的实例。如果我再次调用controllerFor(),则不会创建新实例但是返回第47行中调用创建的实例 - 我发现有点令人困惑。

但是,如果我这样做:http://jsfiddle.net/UzgMd/8/

App = Ember.Application.create();

App.Store = DS.Store.extend({
    revision: 12,
    adapter: 'DS.FixtureAdapter'
});
App.AccountInfo = DS.Model.extend({

    firstName: DS.attr('string'),
    lastName: DS.attr('string'),

    fullName: function() {
        return this.get('firstName') + ' ' + this.get('lastName');
    }.property('firstName', 'lastName')
});

App.AccountInfo.FIXTURES = [{
    id: 1,
    firstName: "John",
    lastName: "Doe"
}];

App.headerController = Ember.ObjectController.extend({}).create(); // works
//App.HeaderController = Ember.ObjectController.extend({}); // doesnt work

App.HeaderView = Ember.View.extend({
    templateName: 'header',

    controller: App.headerController // works
    //controller: App.HeaderController.create() // doesnt work
});
App.SidebarView = Ember.View.extend({
    templateName: 'sidebar'
});

App.ApplicationController = Ember.Controller.extend({});
App.ApplicationRoute = Ember.Route.extend({

    model: function() {
        return App.AccountInfo.find(1);
    },

    setupController: function(controller, model) {
        this._super(controller, model);

        App.headerController.set('model', model); // works
        //this.controllerFor('header').set('content', model); // doesnt work

    }

});

使用单例控制器实例,我注入模型,一切正常。

现在我的问题:

  • controllerFor()是否会创建一个新实例?如果没有,为什么它会像这样或我做错了什么?
  • 我在第二个小提琴中的工作方式是正确的方法,还是有更好的方法?

1 个答案:

答案 0 :(得分:4)

  

我想要一个使用'view'帮助器的应用程序模板来包含其他一些视图。

{{view}}帮助器是合适的,如果你想要的只是一个没有控制器的简单Ember.View。例如Ember.InputField之类的东西。对于应用程序的标题和侧边栏,您通常需要一个由控制器支持的视图。在这种情况下,请使用{{render}}助手。有关详细信息,请查看此blog post

  

我还希望有一些“全局”模型,其中包含我希望能够在不同视图中使用的有关环境的信息(例如登录用户帐户信息等)。

有道理。存储该信息的正确位置在控制器中。这可能是ApplicationController的属性,也可能是currentUserController之类的单独控制器。由于视图应该只访问它自己的控制器的属性,因此您可以使用控制器的needs数组使其可访问。见managing dependencies between controllers

  

controllerFor()是否会创建一个新实例?

不,这不是一个错误。

  

如果没有,为什么它会像这样或我做错了什么?

问题是您正在尝试手动创建headerController的实例。通常,如果您在控制器上调用create(),那么就会出错。 Ember希望自己管理控制器实例,并将它们注册到容器上,以便以后可以找到它们。由于您的实例未注册,因此当您调用controllerFor()时,ember会创建一个新实例。

  

我在第二小提琴中的工作方式是一种正确的方法,还是有更好的方法?

绝对不是正确的方法。在这个小提琴中,你正在使用一个全局变量来完成ember应该自动为你做的事情。这意味着有许多代码是不必要的,并且对象之间存在很多耦合,这使得难以测试。如果你采用{{render}}方法,它将看起来像这样:

<script type="text/x-handlebars" id="application">
    {{render header}}
    {{render sidebar}}
    {{outlet}}
</script>
<script type="text/x-handlebars" id="header">HEADER {{content}}<hr/></script>
<script type="text/x-handlebars" id="sidebar">SIDEBAR {{content}}<hr/></script>


App = Ember.Application.create({});
App.HeaderController = Ember.ObjectController.extend();
App.SidebarController = Ember.ObjectController.extend();
App.IndexRoute = Ember.Route.extend({
    setupController: function() {
      this.controllerFor('header').set('content', 'hi');
      this.controllerFor('sidebar').set('content', 'bye');
    }
});

使用{{render}}我们不需要定义HeaderView或SidebarView,因为ember会自动生成它们。每个都将绑定到其控制器的单例实例,并且可以通过controllerFor从您的路由访问这些控制器。

JSFiddle:http://jsfiddle.net/NQKvy/1/