2015-10-27 22 views
1

我们正在使用的需要允许其他指令/控制器知道树样式导航元素:共享和跨控制器观测数据

  • 什么当前的选择是,和
  • 当行选择变化

我想确定最好的角度来处理这个问题。

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

但是,我们现在需要获取当另一个组件被激活时的当前选择。一个事件不会飞。

所以我正在考虑一个服务,一些持有当前选择的单身人士,可以直接在树上更新,并由任何需要它的人阅读。

然而,目前这个其他一些问题:

  • 它会更好完全沟事件,并有其需要知道什么时候它改变$watch服务的节点ID组件?
  • 如果我使用$watch,好像我应该直接暴露对象 - 所以使用getters/setter将不起作用,除非我想使所需的$watch代码复杂化?我所关注的

部分原因是,这将允许任何组件设置的价值,这是故意不是我们会允许 - 的变化不会影响树,但会取消同步从服务价值真正的价值,并将发射无效$watches

+0

是否整个应用程序需要知道currentSelection,或网站的某一部分?也许将这些信息存储在所有涉及的指令/控制器的共享父控制器中。你可以分享一些涉及的代码(可能是在一个笨蛋?) –

+0

这是一个网络应用程序,所以当你做出选择时,其他一些组件需要知道 - 这是事件运行良好的一部分 - 此外它也可以单程。共享一个父范围值可能会起作用,但我仍然存在的担忧 - 范围上的任何内容都可以设置该值。我可能更喜欢一种服务,这样我们就可以使我们成为DI,并避免潜在的命名冲突。 – helion3

+0

您能否解释一下对于预期的$ watch功能感觉复杂的问题 - 您打算如何实现这一功能? –

回答

0

实现一个getter不应导致一个复杂的$守望者:

服务:

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

控制器:

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

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

0

我认为使用一项服务应该可以工作,而且你不需要任何监督人员。

在下面或在此fiddle我已经添加了以下我的演示:

  1. 一个服务/工厂sharedData多数民众赞成存储数据 - 选择和项目
  2. 事件触发功能sharedDataEvents具有观察员/监听另一个服务模式。

要在component2中显示值,我使用了单向绑定,以便组件不能更改选择。

将事件与事件分离可防止组件更改选择。所以只有MainControllerComponent1可以改变选择。

如果您打开浏览器控制台,您可以看到正在运行的侦听器。只有component3的听众正在做一些事情(在3次选择改变后它会做出警报),其他人只是将新选择记录到控制台。

angular.module('demoApp', []) 
 
\t .controller('MainController', MainController) 
 
\t .directive('component1', Component1) 
 
\t .directive('component2', Component2) 
 
    .directive('component3', Component3) 
 
\t .factory('sharedData', SharedData) 
 
\t .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();     
 
\t this.selection = this.items[0]; 
 
} 
 

 
function Component1() { 
 
    return { 
 
    \t restrict: 'E', 
 
     scope: {}, 
 
     bindToController: { 
 
     \t 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 
 
      \t sharedData.setSelection(item); 
 
      }; 
 
      
 
      sharedDataEvents.addListener('onSelect', function(selected) { 
 
      \t console.log('selection changed comp. 1 listener callback', selected); 
 
      }); 
 
     }, 
 
     controllerAs: 'comp1Ctrl' 
 
    }; 
 
} 
 

 
function Component2() { 
 
    return { 
 
    \t restrict: 'E', 
 
     scope: {}, 
 
     bindToController: { 
 
     \t selection: '@' 
 
     }, 
 
     template: 'Comp2 selection: {{comp2Ctrl.selection}}', 
 
     controller: function(sharedDataEvents) { 
 
      sharedDataEvents.addListener('onSelect', function(selected) { 
 
      \t console.log('selection changed comp. 2 listener callback', selected); 
 
      }); 
 
     }, 
 
     controllerAs: 'comp2Ctrl' 
 
    }; 
 
} 
 

 
function Component3() { 
 
\t //only listening and alert on every third change 
 
    return { 
 
    \t restrict: 'E', 
 
     controller: function($window, sharedDataEvents) { 
 
     \t var count = 0; 
 
      sharedDataEvents.addListener('onSelect', function(selected, old) { 
 
      \t console.log('selection changed comp. 3 listener callback', selected, old); 
 
       if (++count === 3) { 
 
        count = 0; 
 
       \t $window.alert('changed selection 3 times!!! Detected by Component 3'); 
 
       } 
 
      }); 
 
     } 
 
    } 
 
} 
 
function SharedData(sharedDataEvents) { 
 
    return { 
 
    \t selection: {}, 
 
     items: [], 
 
     setItems: function(items) { 
 
     \t this.items = items 
 
     }, 
 
     setSelection: function(item) { 
 
     \t this.selection = item; 
 
      sharedDataEvents.onSelectionChange(item); 
 
     }, 
 
     getItems: function() { 
 
     \t return this.items; 
 
     } 
 
    }; 
 
} 
 

 
function SharedDataEvents() { 
 
\t return { 
 
     changeListeners: { 
 
     \t onSelect: [] 
 
     }, 
 
     addListener: function(type, cb) { 
 
     \t this.changeListeners[type].push({ cb: cb }); 
 
     }, 
 
     onSelectionChange: function(selection) { 
 
      console.log(selection); 
 
      var changeEvents = this.changeListeners['onSelect']; 
 
      console.log(changeEvents); 
 
      if (! changeEvents.length) return; 
 
      
 
     \t 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>

相关问题