路由其中一個很重要的職責就是加載適合的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。