组件如何响应操作?

时间:2014-04-08 17:26:18

标签: ember.js

tl; dr:数据可以发送进出组件,但我只知道如何发送操作。有没有办法发送行动?


在我的Ember应用程序中,我有类似Google地图中的以下用户界面:

enter image description here

背景图对应于PinsRoute / PinsView / PinsController,它显示了许多引脚。点击一个后,输入PinRoute,将叠加层渲染为{{outlet}}。大地图和缩略图(在Google地图图片中,图片中显示"街景")分别是:FullscreenMapComponentThumbnailMapComponent

在Google地图中,当您点击"街景"时,它会将主地图平移并缩放到所选点。这基本上就是我试图弄清楚如何连线。

当用户点击"延伸视图"在ThumbnailMapComponent上,我可以发送PinsRoute可以处理的操作。问题是,我怎样才能到达我的FullscreenMapComponent并调用适当的方法(在这种情况下为.panToSelected())?

2 个答案:

答案 0 :(得分:6)

这是一个很好的解决方案。让组件将自己注册到呈现它的任何控制器,这样你就可以在动作处理程序中访问该组件。

就我而言,我在组件中添加了一个方法

App.FullscreenMapComponent = Ember.Component.extend({

  ...

  _register: function() {
    this.set('register-as', this);
  }.on('init')

});

和我的控制器的属性:

App.SensorsController = Ember.ArrayController.extend({

  fullscreenMap: null,

  ...

});

在我的模板中,我将两者绑定到我的新register-as属性:

// sensors.hbs

  {{fullscreen-map data=mapData
    selectedItem=currentSensor
    action='selectSensor'
    deselect='deselectSensor'
    register-as=fullscreenMap }}

现在,让我说我点击上面的缩略图,它会发送一个冒泡到ApplicationRoute的动作,我现在可以这样做了:

// ApplicationRoute.js

actions: {
  panTo: function(latLong, zoom) {
    this.controllerFor('sensors').get('fullscreenMap').panTo(latLong, zoom);
  }
}

的Presto!响应行动的组件。

更新(2016年10月6日)

哇,我在两年内学到了很多东西。

我不再推荐这个解决方案了。通常,您应该努力使组件具有声明性,并使其输出和行为完全取决于其状态。相反,我在这里的原始答案使用命令式方法解决了问题,这种方法很脆弱,难以理解,并且不容易扩展(如果我们想将地图的位置与URL联系起来怎么办?)。

如果我正在重构此特定组件,我可能会{{fullscreen-map}}接受latLongzoom参数。如果来自外部的人设置了这些,则地图将响应并自行更新。您可以在组件中使用didReceiveAttrs来响应参数更改,然后从那里调用Google API中的命令式panTo方法。

需要注意的是,即使你必须与命令式方法交互(可能是因为第三方库),也要努力使自己组件的API尽可能具有声明性。首先看起来“向下发送一个动作”通常可以表示为状态的一些功能,并且该状态是您想要识别和明确的状态。

答案 1 :(得分:1)

这是一个有效的例子,但我并不是100%确定这种方法是最好的

你可以做什么:

调用action时,将组件作为参数传递:

App.PinController = Ember.Controller.extend({
   actions: {
      actionThatComponentCalls: function(){
         // different component will be called
         new App.MyOtherComponent().send('differentAction'):
      }
   }
});

App.FullScreenMapComponent = Ember.Component.extend({
   click: function(){
     this.sendAction();
   }
});

App.MyOtherComponent = Ember.Component.extend({
   actions: {
     differentAction: function(){
       console.log('different action called');
     }
   }
});

希望这有帮助