在Ember 2.0中存储瞬态UI状态的位置 [英] Where to store transient UI state in Ember 2.0

查看:110
本文介绍了在Ember 2.0中存储瞬态UI状态的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Ember 2.0已经很大程度上使所有的东西成为一个组件。随着可路由组件即将推出,控制器也可能会逐步淘汰。



上下文



然而,在构建用户界面时遇到一个反复出现的问题,我现在没有一个令人满意的模式:用户界面状态。



什么是我正在关注?




  • 选择状态

  • 当前焦点

  • 在某些树状显示中折叠/展开状态



基本上,任何不属于实际数据的状态,但必须在逐个对象的基础上进行跟踪。过去,以前用$ code>控制器来完成模型的代理。这种方法现在已经过时了。新的方法是组件无处不在,为更好。组件做记账,跟踪瞬态,你会采取行动。



然而,我拥有的一个典型模式是共享状态,例如可选项目的列表。



问题



构建列表组件,具有以下要求: / p>


  • 可以选择每个项目。

  • 选择状态更改DOM(某些类绑定) / li>
  • 用户可以在列表组件中绘制一个矩形,以便一次选择多个项目。

  • 理想情况下,整个行为可以抽象出来作为混合。



问题:选择标记在哪里生活?



尝试



1)一切都是一个组件。



我使每个项目成为一个子组件说{{my-list-item}}。组件跟踪选择状态。问题:列表组件如何更新选择状态?



2)从子组件移动状态。



将其放在列表组件上。在项目列表旁边的单独的状态数组中。优点:该列表具有所有需要的状态。缺点:当项目从列表中添加或删除时,保持同步的是一场恶梦。这意味着子组件无法访问该状态。或者也许我可以将它作为绑定值传递给他们?



3)重新引入代理。



想想,有一种方式来分享一些状态:把它放在模型上。那么,不是在实际的模型上,以免污染他们的本地状态,而是通过设置一个ArrayProxy将返回一些 ObjectProxy 为每个项目,以保持状态。



优点:这是我完全实现的唯一解决方案。缺点:项目的封装和解封是一件麻烦。另外,在几层传递之后, get set 必须经历4个5代理,其中我担心会出现性能问题。



此外,它对于mixins来说并不奏效。我应该抽出一些 HasSelection mixin和一个 HasFoldableItems mixin和一个可排序 mixin,他们都需要一些状态。



返回绘图板



我还没有找到更好的模式吗?



我发现了以下相关问题,但这无关紧要:




解决方案

很好的问题 - 我真的去了一个核心的艾伯茶m成员找出答案当前是服务。因为组件最好是无状态(在大多数情况下),您可以利用服务来持久保持不适合服务器持久模型的状态。



这里是一个很好的例子,Stef Penner放在一起显示如何在您的ember应用程序中保存电子邮件草稿(不是后端保留)



https://github.com/stefanpenner/ember-state-services



用于引用的示例组件(从上面的github项目)

 导出默认值Ember.Component.extend({
tagName :'form',
editEmailService:Ember.inject.service('email-edit'),
状态:Ember.computed('email',function(){
return this.editEmailService .stateFor(this.get('email'));
})。readOnly(),

actions:{
save(){
this.get ('state')。applyChanges();
this.sendAction('on-save',this.get 'email'));
},

cancel(){
this.get('state')。discardChanges();
this.sendAction('on-cancel',this.get('email'));
}
}
});


Ember 2.0 has gone great lengths towards making everything a component. With routable components coming soon, controllers will probably phased out as well.

Context

However, there is a recurring problem I face when building User interface, which I don't have a satisfying pattern for so far: user interface state.

What am I taking about?

  • Selection state
  • Current focus
  • Folded/unfolded state in some tree display

Basically, any state that is not part of the actual data, yet has to be tracked on an object-by-object basis. In the past, this used to be done with Controllers, acting as proxies to models. This approach is now obsolete. The new approach is Components everywhere, for the better. Component does the bookkeeping, tracks transient state and you get actions back.

A typical pattern I have, though, is with shared state, such as a list with selectable items.

The issue

Building a list component, with the following requirements:

  • Each item can be selected.
  • Selection state changes the DOM (some class bindings).
  • User can draw a rectangle in the list component to select several items at once.
  • Ideally, the whole behavior can be abstracted out as a mixin.

Question: where does the selection flag live?

Attempts

1) Everything is a component.

I make each item a sub-component, say {{my-list-item}}. The component tracks the selection state. Problem: how can the list component update the selection state?

2) Move state out of sub-components.

Put it on the list component. Within a separate state array alongside the item list. Pros: the list has all the state it needs. Cons: it's a nightmare to keep it synced when items are added or removed from the list. And it means the sub-component have no access to the state. Or maybe I could pass it to them as a bound value?

3) Reintroducing proxies.

Coming to think of it, there is a way to share some state: put it on the models. Well, not on the actual models so as not to pollute them with local state, but by setting up an ArrayProxy that will return some ObjectProxy for every item, to hold the state.

Pros: this is the only solution I managed to implement completely. Cons: encapsulation and decapsulation of items is a hassle. Also, after a few layers of being passed around, get and set have to go through 4 ou 5 proxies, which I fear will be a problem with performance.

Also, it does not work well for mixins. Should I want to abstract out some HasSelection mixin, and a HasFoldableItems mixin, and a Sortable mixin, they all need some state.

Back to the drawing board

Is there some better pattern I have not found?

I found the following relevant questions, but that led me nowhere:

解决方案

Great question - I actually went to one of the core ember team members to find out and the answer currently is services. Because the component is best left stateless (for the most part) you can leverage a service to persist this state that doesn't fit into a server persisted model.

Here is a great example that Stef Penner put together showing how you might save a "email draft" in your ember app (that isn't persisted backend)

https://github.com/stefanpenner/ember-state-services

Example component for reference (from the github project above)

export default Ember.Component.extend({
  tagName: 'form',
  editEmailService: Ember.inject.service('email-edit'),
  state: Ember.computed('email', function() {
    return this.editEmailService.stateFor(this.get('email'));
  }).readOnly(),

  actions: {
    save() {
      this.get('state').applyChanges();
      this.sendAction('on-save', this.get('email'));
    },

    cancel() {
      this.get('state').discardChanges();
      this.sendAction('on-cancel', this.get('email'));
    }
  }
});

这篇关于在Ember 2.0中存储瞬态UI状态的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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