路由其中一个很重要的职责就是加载适合的model,初始化数据,而后在模板上显示数据。javascript
// app/router.js // …… Router.map(function() { this.route('posts'); }); export default Router;
对于posts这个路由若是要加载名为post的model要怎么作呢?代码实现很简单,其实在前面的代码也已经写过了。你只须要重写model回调,在回调中返回获取到的model便可。html
// app/routes/posts.js import Ember from 'ember'; export default Ember.Route.extend({ model: function() { // return Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls'); // 加载post(是一个model) return this.store.query('post'); } });
model回调能够返回一个Ember Data记录,或者返回任何的promise对象(Ember Data也是promise对象),又或者是返回一个简单的javascript对象、数组均可以。可是须要等待数据加载完成才会渲染模板,因此若是你是使用Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');获取远程数据页面上会有一段时间是空白的,其实就是在加载数据,不过这样的用户体验并很差,不过你也不须要担忧这个问题,Ember已经提供了解决办法。还记得上一篇的截图的路由表吗?是否是每一个路由都有一个xxx_loading路由,这个路由就是在数据加载的时候执行的,有关xxx_loading更多详细的信息在后面的博文介绍。java
一个route有时候只加载同一个model,好比路由“/photos”就一般是加载模型photo。若是用户离开或者是从新进入这个路由模型也不会改变。git
然而,有些状况下路由所加载的model是变化的。好比在一个图片展现的APP中,路由“/photos”会加载一个photo模型集合并渲染到模板photos上。当用户点击其中一幅图片的时候路由只加载被点击的model数据,当用户点击另一张图片的时候加载的又是另一个model而且渲染到模板上,并且这两次加载的model数据是不同的。github
在这种情形下,访问的URL就包含了很重要的信息,包括路由和模型。api
在Ember应用中能够经过定义动态段实现加载不一样的模型。有关动态段的知识在前面的《Ember.js 入门指南——{{link-to}} 助手》和《Ember.js 入门指南——路由定义》已经作过介绍。数组
一旦在路由中定义了动态段Ember就会从URL中提取动态段的值做为model回调的第一个参数。promise
// app/router.js // …… Router.map(function() { this.route('posts', function() { this.route('post', { path: '/:post_id'}); }); }); export default Router;
这段代码定义了一个动态段“:post_id”,记得动态段是以“:”开头。而后在model回调中使用动态段获取数据。浏览器
// app/routes/posts.js import Ember from 'ember'; export default Ember.Route.extend({ model: function(params) { return this.store.findRecord('post', params.post_id); } });
能够看到在model回调中也是使用在路由中定义的动态段,并把这个动态段做为参数传递给Ember的方法findRecord,Ember会把URL对应位置上的数据解析到这个动态段上。缓存
注意:在model中的动态段只在经过URL访问的时候才会被解析。若是你是经过其余方式(好比使用link-to进入路由)转入路由的,那么路由中model回调方法里的动态不会被解析,所请求的数据会直接从上下文中获取(你能够把上下文想象成ember的缓存)。下面的代码将为你演示这个说法:
import DS from 'ember-data'; export default DS.Model.extend({ title: DS.attr('string'), body: DS.attr('string'), timestamp: DS.attr('number') });
定义了3个属性,id属性不须要显示定义,ember会默认加上。
Router.map(function() { this.route('posts', function() { this.route('post', { path: '/:post_id'}); }); });
而后用Ember CLI命令(ember g route posts/post)在建立路由post,同时也会自动建立出子模板post.hbs。建立完成以后会获得以下两个文件:
app/routes/posts/post.js
app/templates/posts/post.hbs
// app/routes/posts.js import Ember from 'ember'; export default Ember.Route.extend({ model: function(params) { return [ { "id":"-JzySrmbivaSSFG6WwOk", "body" : "testsssss", "timestamp" : 1443083287846, "title" : "test" }, { "id":"-JzyT-VLEWdF6zY3CefO", "body" : "33333333", "timestamp" : 1443083323541, "title" : "test33333" }, { "id":"-JzyUqbJcT0ct14OizMo" , "body" : "body.....", "timestamp" : 1443083808036, "title" : "title1231232132" } ]; } });
<ul> {{#each model as |item|}} <li> {{#link-to 'posts.post' item}}{{item.title}}{{/link-to}} </li> {{/each}} </ul> <hr> {{outlet}}
// app/routes/posts/post.js import Ember from 'ember'; export default Ember.Route.extend({ model: function(params) { console.log('params = ' + params.post_id); return this.store.findRecord('post', params.post_id); } });
注意打印信息语句console.log();,而后接着修改子模板post.hbs。
<!-- app/templates/posts/post.hbs --> <h2>{{model.title}}</h2> <p>{{model.body}}</p>
到此,所有所需的测试数据和代码已经编写完毕。下面执行http://localhost:4200/posts,能够看到界面上显示了全部在路由posts的model回调中设置的测试数据。查看页面的HTML代码:
能够看到每一个链接的动态段都被解析成了数据的id属性值。
注意:随便点击任意一个,注意看浏览器控制台打印的信息。
我点击了以第一个链接,浏览器的URL变为
看浏览器的控制台是否是并无打印出“params = -JzySrmbivaSSFG6WwOk”,在点击其余的链接结果也是同样的,浏览器控制台没有打印出任何信息。
下面我咱们直接在浏览器地址栏上输入:http://localhost:4200/posts/-JzyUqbJcT0ct14OizMo而后按enter执行,注意看浏览器控制台打印的信息!!!此时打印了“params = -JzyUqbJcT0ct14OizMo”,你能够用一样的方式执行另外两个连接的地址。一样也会打印出“params = xxx”(xxx为数据的id值)。
我想这个例子应该能很好的解释了Ember提示用户须要的注意的问题:
只有直接用过浏览器访问才会执行包含了动态段的model回调,不然不会执行包含有动态段的回调;
若是没有包含动态段的model回调不论是经过URL访问仍是经过link-to访问都会执行。
你能够在路由posts的model回调中添加一句打印日志的代码,而后经过点击首页上的about和posts切换路由,你能够看到控制台打印出了你在model回调中添加的日志信息。
对于在一个model回调中同时返回多个模型的状况也是时常存在的。对于这种状况你须要在model回调中修改返回值为Ember.RSVP.hash对象类型。好比下面的代码就是同时返回了两个模型的数据:一个是song,一个是album。
// app/routes/favorites.js import Ember from 'ember'; export default Ember.Route.extend({ model: function() { return Ember.REVP.hash({ songs: this.store.find('song'), albums: this.store.find('slbum') }); } });
而后在模板favorites.hbs中就可使用{{#each}}把两个数据集遍历出来。遍历的方式与普通的遍历方式同样。
<!-- app/templates/favorites.hbs --> <h2>Song list</h2> <ul> {{#each model.songs as |item|}} <li>{{item.name}}</li> {{/each}} </ul> <hr> <h2>Album list</h2> <ul> {{#each model.albums as |item|}} <li>{{item.name}}</li> {{/each}} </ul>
到此全部路由的model回调的状况介绍完毕,model回调其实就是把模型绑定到路由上。实现数据的初始化,而后把数据渲染到模板上显示。 这也是Ember推荐这么作的—就是把操做数据相关的处理放在route而不是放在controller。