繁体   English   中英

跨控制器共享和观察数据

[英]Sharing and observing data across controllers

我们正在使用树型导航元素,该元素需要允许其他指令/控制器知道:

  • 当前选择是什么,以及
  • 当行选择更改时

我正在尝试确定处理此问题的最佳方法。

到目前为止,我们一直在引发整个应用程序可以收听的事件-不够理想,但要确保没有硬编码直接与组件进行通信。

但是,我们现在需要在激活另一个组件时获得当前选择。 活动不会进行。

因此,我正在考虑一种服务,该服务可以保存当前选择,并且可以由树直接更新,并可由需要它的任何人读取。

但是,这带来了其他一些问题:

  • 最好完全放弃该事件,并让组件知道何时更改$watch服务的nodeId?
  • 如果我使用$watch ,似乎应该直接暴露该对象-因此,除非我想使所需的$watch代码复杂化,否则使用getters / setter方法将无法工作?

我担心的一部分是,这将允许任何组件设置该值,而我们故意不允许这样做-更改不会影响树,但会使服务值与真实值不同步,并且会触发无效值$watches

实现吸气剂不应导致复杂的$ watcher:

服务:

angular.service('myService', function() {
  var privateVar = 'private';
  return {
    getter: function() {
      return privateVar;
  };
});

控制器:

angular.controller('myController', function(myService){
  $scope.watch(myService.getter, function(){
    //do stuff
  };
});

看到这个矮人: http ://plnkr.co/edit/kLDwFg9BtbkdfoSeE7qa?p=preview

我认为使用服务应该可以,并且您不需要任何观察者。

在下面的演示中或此小提琴中,我添加了以下内容:

  1. 一种服务/工厂sharedData数据,用于存储数据-选择和项目
  2. 使用观察者/侦听器模式来事件sharedDataEvents另一项服务。

为了显示component2的值,我使用了单向绑定,因此该组件无法更改选择。

同样,将数据与事件分开也可以防止组件更改选择。 因此,只有MainControllerComponent1可以更改选择。

如果要打开浏览器控制台,则可以看到监听器正在运行。 只有component3侦听器正在做某事(更改3个选择后,它将发出警报),其他监听器仅将新选择记录到控制台。

 angular.module('demoApp', []) .controller('MainController', MainController) .directive('component1', Component1) .directive('component2', Component2) .directive('component3', Component3) .factory('sharedData', SharedData) .factory('sharedDataEvents', SharedDataEvents); function MainController(sharedData) { sharedData.setItems([{ id: 0, test: 'hello 0' }, { id: 1, test: 'hello 1' }, { id: 2, test: 'hello 2' }]); this.items = sharedData.getItems(); this.selection = this.items[0]; } function Component1() { return { restrict: 'E', scope: {}, bindToController: { selection: '=' }, template: 'Comp1 selection: {{comp1Ctrl.selection}}'+ '<ul><li ng-repeat="item in comp1Ctrl.items" ng-click="comp1Ctrl.select(item)">{{item}}</li></ul>', controller: function($scope, sharedData, sharedDataEvents) { this.items = sharedData.getItems(); this.select = function(item) { //console.log(item); this.selection = item sharedData.setSelection(item); }; sharedDataEvents.addListener('onSelect', function(selected) { console.log('selection changed comp. 1 listener callback', selected); }); }, controllerAs: 'comp1Ctrl' }; } function Component2() { return { restrict: 'E', scope: {}, bindToController: { selection: '@' }, template: 'Comp2 selection: {{comp2Ctrl.selection}}', controller: function(sharedDataEvents) { sharedDataEvents.addListener('onSelect', function(selected) { console.log('selection changed comp. 2 listener callback', selected); }); }, controllerAs: 'comp2Ctrl' }; } function Component3() { //only listening and alert on every third change return { restrict: 'E', controller: function($window, sharedDataEvents) { var count = 0; sharedDataEvents.addListener('onSelect', function(selected, old) { console.log('selection changed comp. 3 listener callback', selected, old); if (++count === 3) { count = 0; $window.alert('changed selection 3 times!!! Detected by Component 3'); } }); } } } function SharedData(sharedDataEvents) { return { selection: {}, items: [], setItems: function(items) { this.items = items }, setSelection: function(item) { this.selection = item; sharedDataEvents.onSelectionChange(item); }, getItems: function() { return this.items; } }; } function SharedDataEvents() { return { changeListeners: { onSelect: [] }, addListener: function(type, cb) { this.changeListeners[type].push({ cb: cb }); }, onSelectionChange: function(selection) { console.log(selection); var changeEvents = this.changeListeners['onSelect']; console.log(changeEvents); if ( ! changeEvents.length ) return; angular.forEach(changeEvents, function(cbObj) { console.log(typeof cbObj.cb); if (typeof cbObj.cb == 'function') { // callback is a function if ( selection !== cbObj.previous ) { // only trigger if changed cbObj.cb.call(null, selection, cbObj.previous); cbObj.previous = selection; // new to old for next run } } }); } }; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.js"></script> <div ng-app="demoApp" ng-controller="MainController as ctrl"> <p>Click on a list item to change selection:</p> <component1 selection="ctrl.selection"></component1> <!-- can change the selection --> <component2 selection="{{ctrl.selection}}"></component2> <component3></component3> </div> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM