4.4 Routing -- Specifying A Route's Model

一、概述

应用程序中,templates被models支持。但是templates是如何知道它们应该显示哪个model呢?

例如,你有一个photos模板,它是如何知道它该呈现哪个model呢?

这就是Ember.Route工作的一部分。你可以通过定义一个和template同名的route来告诉模板呈现哪个模型,并且实现model hook

例如,为photos模板提供一些model属性,我们定义一个route:photos对象:

app/routes/photos.js

export default Ember.Route.extend({
  model() {
    return [{
      title: "Tomster",
      url: "http://emberjs.com/images/about/ember-productivity-sm.png"
    }, {
      title: "Eiffel Tower",
      url: "http://emberjs.com/images/about/ember-structure-sm.png"
    }];
  }
});

二、Asynchronously Loading Models(异步加载模型)

1. 在上面的示例中,模型数据是从model hook被同步返回的。这意味着数据可以立即使用,你的app不需要等待它加载,在这种情况下,因为我们马上返回数组的硬编码数据。

2. 当然,这不总是现实的。通常,数据同步将不可用,但是相反必须通过网络异步加载。例如,我们可以通过一个服务器上可用JSON API来检索照片列表。

3. 在异步数据可用的情况下,你可以从model hook仅仅返回一个promise,在呈现模板前Ember会一直等待,直到这个promise被解决。

3. 如果你对promises不熟悉,它的基本思路是,它们是代表最终值的对象。例如,如果你使用jQuery的getJSON()方法,它将会为最终通过网络返回的JSON返回一个promise。Ember使用这个promise对象去了解什么时候它有足够的数据去渲染。

4. 看一个例子。这是一个路由,它加载GitHub上最近发送到Ember.js的pull request:

app/routes/pull-requests.js

export default Ember.Route.extend({
  model() {
    return Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');
  }
});
  • 虽然这个例子看起来是同步的,因此很容易阅读和推理,它实际上完全是异步的。
  • 因为jQuery的getJSON()方法返回一个promise。Ember检测到从一个model hook中返回了一个promise,并等待,直到这个promise解决呈现pullRequests模板。

5. 因为Ember支持promises,它可以和任何使用它们作为它的公共API的一部分的存在的库一起工作。你还可以基于promises使用很多便利使代码变得更好。

6. 例如,设想如果你需要修改上面的例子,以便模板仅仅显示最近三个pull requests。在数据传递到模板之前,我们可以依赖promise链去修改从JSON请求中返回的数据。

app/routes/pull-requests.js

export default Ember.Route.extend({
  model() {
    var url = 'https://api.github.com/repos/emberjs/ember.js/pulls';
    return Ember.$.getJSON(url).then(function(data) {
      return data.splice(0, 3);
    });
  }
});

三、Setting Up Controllers With The Model

所以从model hook中返回的值实际上发生了什么?

1. 默认的,从model hook返回的值将被指派给model属性相关的controller。例如,如果你的route:posts从它的model hook返回一个对象,这个对象将被设置为controller:postsmodel属性。

(这一点,私底下,模板是如何知道去加载哪一个model:它们需找它们相关的controllermodel属性。例如,photos模板将会呈现,无论controller:photosmodel被设置为什么。)

2. 默认行为可以被改变。注意,如果你重写默认行为但是不给controller设置model属性的话,你的模板不会呈现任何数据。

四、Dynamcic Models

1. 一些路由通常展现同样的model。例如,在应用程序中路由/photos通常展现相同的photos列表。如果用户离开这个route并且稍后返回,model不会改变。

2. 然而,你会有一个路由,它的model会根据用户交互改变。例如,假设一个photo viewer app。/photos路由将会用photos列表作为model渲染photos模板,这个从来不会变。但是当用户点击一个指定的照片,我们希望用photo模板展示该模型。如果用户返回并且点击一个不同的照片,我们希望再一次展示photo模板,这次是用一个不同的model。

3. 在这样的情况下,在URL中不仅包括要显示的模板而且还包括model,这很重要。

4. 在Ember中,这是通过使用动态字段定义路由来实现的。

5. 一个动态字段是URL的一部分,它使用当前model的id来填充。动态字段通常以":"开始。

我们的photo例子定义的photo路由:

Router.map(function() {
  this.route('photo', { path: '/photos/:photo_id' });
});
  • 在例子中,photo路由有一个动态字段:photo_id。当用户进入photo路由去展现一个指定的model(通常通过{{#link-to}})时,模型的id将会被自动放入URL中。

6. 例如,如果你转换到photo路由,使用一个id为47的model,用户浏览器中的URL将会被更新为:/photos/47

7. 如果用户通过包含动态字段的URL直接访问app会发生什么?例如,他们可能会UI重新加载页面,或者向朋友发送链接。在这一点上, 因为我们是从暂存器启动app的,实际上JS model对象已经丢失了,我们有的仅仅是从URL上得到的ID。

8. 幸运的是,Ember将会从URL上提取任何动态字段并且将它们作为一个hash传递到model hook,作为它的第一个参数。

app/router.js 

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

app/routes/photo.js

export default Ember.Route.extend({
  model(params) {
    return Ember.$.getJSON('/photos/'+params.photo_id);
  }
});

在model hook中对于有动态字段的路由,你的工作是把ID传入一个model,它可以被路由的模板渲染。在上面的例子中,我们用照片的ID构造一个URL用于该照片的JSON表示。一旦我们拥有了URL,我们使用jQuery来为JSON模型数据返回一个promise。

9. 注意,当直接通过URL进入路由时,一个有动态字段的路由将会仅仅调用它的modle hook。如果route是通过跳转(例如link-to)进入的,模型上下文已经存在了并且钩子方法不会执行。没有动态字段的路由仍然执行model hook。

五、Refreshing Your Model

如果你的模型数据更新频繁,你可能想要定期刷新:

controller可以传递一个action给route。在上面的例子中,IndexController暴露一个getLatest action,它传递一个action调用invalidateModel。调用路由的refresh方法将会前置Ember再一次执行model hook。

六、Ember Data

许多Ember开发者使用一个model库来更容易的查找和存储记录,这比手动调用Ajax更简单。特别的,使用一个model库允许你缓存已经加载的记录,显著提高应用程序的性能。

一个流行的基于Ember的model库是Ember Data。

posted @ 2016-01-25 14:34  鱼不吐泡泡  阅读(442)  评论(0编辑  收藏  举报