EmberJS 2.14:使用组件复用路由动作失败,如何实现DRY应用?
嘿,我完全懂你在Ember 2.14里搞DRY应用时遇到的头疼事——组件触发路由动作失败,还报找不到saveStuff的错对吧?这个问题的核心是组件的动作上下文默认不是路由,它只会在自己或父组件/控制器的动作里找,所以直接绑路由的动作自然找不到。下面给你几个适配Ember 2.14的解决方案,从快速修复到更符合DRY的优化都有:
方案1:通过控制器代理路由动作
Ember模板的默认上下文是控制器,所以我们可以在控制器里把路由的动作“转发”出去。如果你的new路由还没有控制器,先新建一个:
// app/controllers/new.js export default Ember.Controller.extend({ actions: { saveStuff(newStuff) { // 调用路由里的同名动作 this.send('saveStuff', newStuff); } } });
之后你的new.hbs不用改,组件就能通过控制器找到路由的saveStuff动作了——控制器相当于中间层,把模板的动作请求转发给路由。
方案2:直接指定动作的目标为路由
在Ember 2.14里,你可以给action助手指定target参数,直接把动作的执行目标指向当前路由,这样就能跳过控制器直接触发路由动作:
{{basic-button texte="Create" theAction=(action 'saveStuff' model target=this.route)}}
这里的this.route在模板上下文里就是当前的路由实例,动作会直接调用路由里的saveStuff方法,简单直接。
方案3:用服务封装复用逻辑(终极DRY方案)
如果这个保存逻辑需要在多个地方复用,把它抽成服务是最符合DRY原则的做法——把业务逻辑集中在一个地方,哪里需要就注入哪里,不用在每个路由里重复写代码。
首先新建一个处理Stuff逻辑的服务:
// app/services/stuff-manager.js export default Ember.Service.extend({ // 注入路由服务用来做页面跳转 router: Ember.inject.service(), saveStuff(newStuff) { return newStuff.save().then(() => { this.get('router').transitionTo('stuffs'); }); } });
然后在你的组件里注入这个服务,把保存逻辑移到组件里:
// app/components/basic-button.js export default Ember.Component.extend({ stuffManager: Ember.inject.service(), actions: { handleSave() { this.get('stuffManager').saveStuff(this.get('model')); } } });
最后修改模板,绑定组件自己的动作:
{{basic-button texte="Create" theAction=(action 'handleSave') model=model}}
这样不管是在哪个路由或组件里,只要注入这个服务就能复用保存逻辑,彻底避免重复代码。
为什么原来的代码会报错?
你之前的代码里,(action 'saveStuff' model)是在模板上下文(默认是控制器)里找saveStuff动作,但路由的actions并不会暴露在模板上下文里,所以组件找不到这个动作,就抛出了那个断言错误。
内容的提问来源于stack exchange,提问作者Syl

