2015-10-27 49 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>

相關問題