是否存在关于接口状态(与持久模型状态相对)应该存在于Ember.js应用程序中的官方故事?
在Router docs的“响应用户启动的事件”部分中,有一个将点击事件委派给照片的“showPhoto”方法的示例,但是模型“show”本身似乎是一种不合需要的混合关注点。
据我所知,在很多情况下,状态应该存储在路由器中,以便接口状态在URL中表示,并在刷新页面或将URL发送给某人时恢复。但是非分层状态呢,例如页面上选择的项目列表?
理想情况下,这种类型的状态会被序列化为查询/哈希参数(例如:http://www.hipmunk.com/flights/QSF-to-NYC#!dates=Sep15,Sep16p1;kind=flight&locations=QSF,YYZ&dates=Sep15,Sep23~tab=1)但据我所知,路由器不提供该功能,是吗?
在BackboneConf,Jeremy Ashkenas表示,在Backbone中做到这一点的正确方法是将状态存储在模型上(他有一个带有“选定”字段的模型示例)。 但是我相信汤姆戴尔说他认为这不是一个好主意,而不是在Ember应该怎么做。不幸的是,我不记得他提到应该如何完成。
答案 0 :(得分:4)
如果您希望状态可路由(即可通过URL访问),则需要通过ember的路由器进行序列化和反序列化。如果状态是瞬态的而不是可路由的,那么它最好保留在控制器上。
如果需要在多个模型中表示复杂的接口状态(例如,用于选择列表中的项目),请考虑维护一个特定于控制器的对象数组,以包装基础数据模型。我认为直接在模型上表示视图状态是不明智的,特别是如果这些模型用于多个视图。
对于您提供的示例,您可能会执行以下操作来连接复杂路线:
Ember.Route.extend({
route: "flights/:cities/dates/:dates",
serialize: function(router, context){
return {cities: context.get('cities'),
dates: context.get('dates')};
},
deserialize: function(router, params){
// return a context object that will be passed into connectOutlets()
return {cities: params.cities,
dates: params.dates};
},
connectOutlets: function(router, context) {
// pass the context from deserialize() in as the content of a FlightController
router.get('applicationController').connectOutlet('flight', context);
}
})
请注意,您还可以使用“flight?cities =:cities& dates =:dates”等路线,但上述内容可能更清晰,更适合搜索引擎优化。
在Gabriel的评论之后扩展:如果你想维护一系列搜索,每个搜索都在自己的标签中,我建议在应用程序级别保留这些搜索的数据数组(例如App.currentUser.activeSearches)。我的理由是,您不希望每次用户切换选项卡时都必须重新创建此数据。相反,路由器将在deserialize()
中检索此数据,然后将其作为上下文传递给connectOutlets()
。在切换选项卡时,应根据此对象快速重新构建表示此数据的视图和控制器。让我从上面扩展我的例子:
Ember.Route.extend({
route: "flights/:cities/dates/:dates",
serialize: function(router, context){
return {cities: context.get('cities'),
dates: context.get('dates')};
},
deserialize: function(router, params){
// find or create a "Search" object that contains the filters and results,
// which will be passed into connectOutlets()
return App.currentUser.findOrCreateSearch({cities: params.cities,
dates: params.dates});
},
connectOutlets: function(router, context) {
// pass the context (a search object) from deserialize() in as the content of a FlightController
router.get('applicationController').connectOutlet('flight', context);
}
})