星期四, 2月 09, 2017

Angular $rootScope and $scope Event System

Angular官方對的 $rootScope 的定義如下
Every application has a single root scope. All other scopes are descendant scopes of the root scope. Scopes provide separation between the model and the view, via a mechanism for watching the model for changes. They also provide event emission/broadcast and subscription facility.
 一個ng-app只會有一個 $rootScope,所有的 $scope 都是 $rootScope 的child scope。文件特別把angular的emission/broadcast機制放在定義,這也代表事件處理是 $rootScope 很重要的操作。

$scope.$emit up, $scope.$broadcast down


// firing an event upwards
$scope.$emit('myCustomEvent', 'Data to send');

// firing an event downwards
$scope.$broadcast('myCustomEvent', {
  someProp: 'Sending you an Object!' // send whatever you want
});

// listen for the event in the relevant $scope
$scope.$on('myCustomEvent', function (event, data) {
  console.log(data); // 'Data to send'
});


簡單說明這三個行為

  • $emit 往上(parent)觸發事件
  • $broadcast 往下(child)觸發事件
  • $on 當收到事件所執行的行為


但是$scope的互動並非都是parent-child關係,有可能是Sibling之間要觸發。這時候就會要先$emit parentScope在$broadcast,並不是很方便的寫法。


$scope.$parent.$broadcast('myevent', 'Some data');


$rootScope.($emit/$broadcast)


上面的這種sibling的事件觸發,則可以使用$rootScope代為處理,如下方案例。
簡單說明 $rootScope 的 $emit 跟 $broadcast 的差別。
  • $rootScope.$emit 因為$rootScope沒有父層,所以直接觸發 $rootScope 註冊的事件。
  • $rootScope.$broadcast 往下廣播事件。

<div ng-controller="ParentCtrl as parent" class="ng-scope">
  // ParentCtrl
  <div ng-controller="SiblingOneCtrl as sib1" class="ng-scope">
    // SiblingOneCtrl
  </div>
  <div ng-controller="SiblingTwoCtrl as sib2" class="ng-scope">
    // SiblingTwoCtrl
    <div ng-controller="ChildCtrl as child" class="ng-scope">
      // ChildCtrl
    </div>
  </div>
</div>



app.controller('SiblingOneCtrl',
  function SiblingOneCtrl ($rootScope) {

  $rootScope.$on('rootScope:emit', function (event, data) {
    console.log(data); // 'Emit!'
  });
  
  $scope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });
  
  $rootScope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });

});

app.controller('ChildCtrl',
  function ChildCtrl ($rootScope) {

  $rootScope.$emit('rootScope:emit', 'Emit!'); // $rootScope.$on
  $rootScope.$broadcast('rootScope:broadcast', 'Broadcast'); // $rootScope.$on && $scope.$on

});


Ref.1 AngularJS Offical Document: $rootScope
Ref.2 Understanding Angular’s $scope and $rootScope event system $emit, $broadcast and $on