Ember.js - 应该在哪里存储界面状态? [英] Ember.js - where should interface state be stored?

查看:109
本文介绍了Ember.js - 应该在哪里存储界面状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



在对用户响应中,接口状态(与持久模式状态相反)是否应该存在于Ember.js应用程序中? -initiated Events部分路由器文档,有一个例子将点击事件委托给照片的showPhoto方法,但是有一个模型显示本身似乎是一个不理想的混合问题。



我知道在许多情况下,状态应该存储在路由器中,以便在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的做法是将状态存储在模型上(他有一个具有selected字段的模型的例子)。
但是我相信汤姆·戴尔(Tom Dale)说,他并不认为这是一个好主意,而不是如何在Ember做的。不幸的是,我不记得他提到它应该如何完成。

解决方案

如果你想要状态可路由(即可通过url访问),然后需要通过ember的路由器进行串行化和反序列化。如果状态是短暂的,而不是可路由的,则可能最好保存在控制器上。



如果需要在多个模型之间表示复杂的接口状态(例如,用于选择列表中的项目),请考虑维护包含基础数据的对象的特定于控制器的数组楷模。我认为直接在模型上表示视图状态是很奇怪的,特别是如果这些模型被用在多个视图中。



对于你提供的例子,你可以这样做挂接一条复杂的路线:

  Ember.Route.extend({
route:flights /:cities / dates /:dates,

serialize:function(router,context){
return {cities:context.get('cities'),
dates:context.get('日期')};
},

deserialize:function(router,params){
//返回一个将传递给connectOutlets()的上下文对象
return {cities:params.cities,
dates:params.dates};
},

connectOutlets:function(router,context){
//传递作为FlightController
router.get('applicationController')的内容的deserialize()的上下文connectOutlet('flight',context);
}
})

不你还可以使用诸如flights?cities =:cities& dates =:dates的路线,但上面可能更干净,更SEO友好。






在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){
//查找或创建一个包含过滤器和结果的搜索对象,
//将被传递到connectOutlets()
return App.currentUser.findOrCreateSearch({cities:params.cities,
dates:params.dates});
} ,

connectOutlets:function(router,context){
//将deserialize()中的上下文(一个搜索对象)作为FlightController的内容
router.get ('applicationController')。connectOutlet('flight',context);
}
})


Is there an official story for where interface state (as opposed to persisted model state) should live in an Ember.js app?

In the "Responding to User-initiated Events" part of the Router docs, there's an example of delegating click events to a photo's "showPhoto" method, but having a model "show" itself seems like an undesirable mixing of concerns.

I understand that in many cases state should be stored in the router so that the interface state is represented in the URL and is restored if you refresh the page or send the url to someone. But what about non-hierarchical state, such as the list of items selected on a page?

Ideally that type of state would be serialized as query/hash params (eg: http://www.hipmunk.com/flights/QSF-to-NYC#!dates=Sep15,Sep16p1;kind=flight&locations=QSF,YYZ&dates=Sep15,Sep23~tab=1 ) but as far as I know, the router doesn't offer that functionality, does it?

At BackboneConf, Jeremy Ashkenas said that the right way to do that in Backbone was to just store the state on the model too (he had an example of a model with a "selected" field). But I believe Tom Dale said he didn't think that was a good idea, and not how it should be done in Ember. Unfortunately I don't remember him mentioning how it should be done.

解决方案

If you want state to be routable (i.e. reachable via a url), then it needs to be serializable and deserializable via ember's router. If state is transient and not routable, then it is probably best kept on the controller.

If you need to represent complex interface state across multiple models (say, for selecting items in a list), consider maintaining a controller-specific array of objects that wrap underlying data models. I think it's hackish to represent view state directly on models, especially if those models are used across multiple views.

For the example you provided, you might do something like this to hook up a complex route:

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);
  }
})

Note that you could also use a route such as "flights?cities=:cities&dates=:dates" but the above is probably cleaner and more SEO-friendly.


Expanded upon after Gabriel's comments: If you want to maintain an array of searches, each of which resides in its own tab, I'd recommend keeping the data for those searches in an application-level array (e.g. App.currentUser.activeSearches). My reasoning is that you don't want to have to recreate this data every time a user switches tabs. Instead, the router would retrieve this data in deserialize() and then pass it as the context to connectOutlets(). The view and controller to represent this data should be quickly re-constructed based upon this object when switching tabs. Let me extend my example from above:

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);
  }
})

这篇关于Ember.js - 应该在哪里存储界面状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆