6.1 Controllers -- Introduction
一、Controllers
1. 在Ember.js中,controllers允许你使用展现逻辑装饰你的models。通常,models将会有保存到服务器的属性,然而controllers将会有不需要保存到服务器的属性。
2. 例如,如果你正在创建一个blog,你想有一个BlogPost model展现blog_post模板。
3. 你的BlogPost model可能会有像这样的属性:
- title
- intro
- body
- author
4. 你的模板将会在blog-post模板中绑定这些属性:
app/templates/blog-post.hbs
<h1>{{model.title}}</h1> <h2>by {{model.author}}</h2> <div class='intro'> {{model.intro}} </div> <hr> <div class='body'> {{model.body}} </div>
5. 在这个简单的例子中,我们还没有任何显示特定的属性或者actions。到目前为止,对model属性来说,我们的controller的model属性仅仅扮演一个传递角色。(记住,一个controller从他对应的route handler中获得model)。
6. 我们想添加一个功能,它将允许用户切换body部分的显示。为了实现它,我们将首先修改模板来展示body,仅仅如果一个新的isExpaned属性的值是true。
app/templates/blog-post.hbs
<h1>{{model.title}}</h1> <h2>by {{model.author}}</h2> <div class='intro'> {{model.intro}} </div> <hr> {{#if isExpanded}} <button {{action 'toggleProperty' 'isExpanded'}}>Hide Body</button> <div class='body'> {{model.body}} </div> {{else}} <button {{action 'toggleProperty' 'isExpanded'}}>Show Body</button> {{/if}}
你可能会考虑应该把这个属性放在model中,但是body是否被expanded严格来说是一个显示问题。
把这个属性放在controller中,可以清晰的将相关的显示逻辑和相关的data model逻辑分离。这将使model单元测试更加容易而不用担心显示逻辑爬进你设置的测试。
二、A note on Coupling(关于耦合的说明)
1. 在Ember.js中,模板从controllers中获取它们的属性,这些属性装饰一个model。
2. 这意味着templates了解controllers并且controllers了解models,但是反过来的话则不然。一个model根本不知道哪一个controller正在装饰它,并且一个controller不知道哪一个模板在显示它的属性。
3. 示意图
4. 这也意味着,作为一个template,所有的属性都来自controller,并且它不需要直接了解model。
5. 实际上,Ember.js将会为整个应用程序创建一个模板的controller一次,但是在应用程序的整个生命周期中controller的model可能会改变,不需要模板知道这些操作的任何内容。
6. 例如,如果用户从/posts/1导航到/posts/2,controller的model将会从store.findRecord('post', 1)变为store.findRecord('post', 2)。在model中该模板将会更新它表示的任何属性,以及controller中依赖于model的任何依赖计算属性。
7. 通过使用一个controller对象渲染它,这使得测试一个模板很容易。这个controller对象包含模板需要的属性。从模板的角度来看,一个controller是一个简单的对象,它提供它的数据。
三、Representing Models
通常,通过一个controller或者component为模板提供context,而不是一个model。这使得很容易将指定的展现属性和指定的model属性分离,并且当用户导航页面时切换一个controller的model。
四、Storing Application Properties
1. 注意应用程序中所有的属性需要被存到服务器。任何时候,你需要仅仅为这个应用程序运行的生命周期存储信息,你可以存储它到一个controller中。
2. 例如,假设你的应用程序有一个一直存在的search field。你应该存贮一个search属性到你的ApplicationController,并且在这个application模板中绑定search field到一个属性,像这样:
app/templates/application.hbs
<header> {{input type="text" value=search action="query"}} </header> {{outlet}}
app/controllers/application.js
export default Ember.Controller.extend({ // the initial value of the `search` property search: '', actions: { query() { // the current value of the text field var query = this.get('search'); this.transitionToRoute('search', { query }); } } });
application的模板存储它的属性并且发送它的actions到ApplicationController。在这种情况下,当用户点击进入,这个应用程序将会跳转到search路由,传递query作为一个参数。