#3 给路由分配模型

时间:2021-08-10 11:10:45

英文模板:https://guides.emberjs.com/v2.13.0/routing/specifying-a-routes-model/

通常,你可能会需要通过模板来展示从model中获得的数据。读取正确的模型数据是路由的职责之一。

比如,下面这个路由:

app/router.js

Router.map(function() {
  this.route('favorite-posts');
});

为了从favorite-posts路由中读取数据,你需要通过model()钩子函数来达到目的:

app/routes/favorite-posts.js

import Ember from 'ember';

export default Ember.Route.extend({
  model() {
    return this.get('store').query('post', { favorite: true });
  }
});

通常,model()钩子会返回Ember Data 记录,但是它也可以返回promise对象(Ember Data记录也是promise对象),普通的javascript对象或数组。Ember会一直等到数据读取完成后(即promise被resolved后)才会渲染模型。

接着,路由会将model()钩子的返回值绑定到其controller的model属性上。然后你就可以在模板中通过controller的model属性来展示数据了。

app/templates/favorite-posts.hbs <h1>Favorite Posts</h1> {{#each model as |post|}} <p>{{post.body}}</p> {{/each}}

动态模型

一些路由总是显示固定的模型。比如,/photos路由总是固定显示你应用中可用的相片的列表。而且当用户离开这个路由,并且再次访问它时,这个被展示的模型并不会变化。

然而,你肯定会需要这样一个路由:它所展示的模型会根据用户的交互做出调整。你可以想象一个你接触过的可以浏览相片的web app。/photos路由会将照片列表作为模型来渲染,这个画面不变。但是当用户点击一个照片的时候,我们想要通过显示单独照片的模板来展示模型数据。并且如果用户后退,然后再次点击一个不同的照片后,我们就再次展示显示单独照片的模板,但是这次的模型数据不同。

在这种情况下,我们就需要在URL中包含一些数据,这些数据不仅决定要显示的模板,还要决定读取的模型。

在Ember中,这些都可以通过在路由中定义动态段来完成。

一旦你实用动态段来定义路由,那么Ember 就会将帮你把动态段对应的值从URL中提取出来,并且将它做为第一个参数传给 model()钩子:

app/router.js

Router.map(function() {
  this.route('photo', { path: '/photos/:photo_id' });
});
app/routes/photo.js

import Ember from 'ember';

export default Ember.Route.extend({
  model(params) {
    return this.get('store').findRecord('photo', params.photo_id);
  }
});

在带有动态段的路由的model()钩子中,你需要在模型中带一个ID,路由模板需要它来进行渲染。在上面例子中,我们将照片id (params.photo_id) 作为参数传入Ember Data的findRecord()中。

【注】:带有动态段的路由会在当你通过URL访问的时候调用model()钩子。但是,如果你通过transition(使用link-to的时候),并且提供了model的上下文(link-to的第二个参数),那么model()钩子不会执行。再但是,如果你传的参数是一个标识符(比如id),那么model()会执行

例子,通过transition行为访问phote路由将不会触发model()钩子,因为一个model对象被传入link-to助手:

app/templates/photos.hbs <h1>Photos</h1> {{#each model as |photo|}} <p> {{#link-to 'photo' photo}} <img src="{{photo.thumbnailUrl}}" alt="{{photo.title}}" /> {{/link-to}} </p> {{/each}}

不过你用这种方式来transition会触发model()钩子(因为link-to收到的是标识符):

app/templates/photos.hbs <h1>Photos</h1> {{#each model as |photo|}} <p> {{#link-to 'photo' photo.id}} <img src="{{photo.thumbnailUrl}}" alt="{{photo.title}}" /> {{/link-to}} </p> {{/each}}

不带动态段的路由将总是触发model()。

多模型

通过RSVP.hash可以一次性返回多个模型。RSVP.hash接受返回promise对象的参数,并且当所有的promise被resolved后,RSVP.hash才会被resolved。例:

app/routes/songs.js

import Ember from 'ember';
import RSVP from 'rsvp';

export default Ember.Route.extend({
  model() {
    return RSVP.hash({
      songs: this.get('store').findAll('song'),
      albums: this.get('store').findAll('album')
    });
  }
});

在songs模板中,我们指定了2个模型,然后可以通过{{#each}}助手分别将song模型和album模型展示出来:

app/templates/songs.hbs <h1>Playlist</h1> <ul> {{#each model.songs as |song|}} <li>{{song.name}} by {{song.artist}}</li> {{/each}} </ul> <h1>Albums</h1> <ul> {{#each model.albums as |album|}} <li>{{album.title}} by {{album.artist}}</li> {{/each}} </ul>

本节完