2016-11-22 51 views
3

爲什麼在本示例中需要$rootScope.$apply()更新頁面上使用ng-hide的元素?

以我的經驗,每當我把$scope.$apply()放在$scope.$watch的內部,我就會得到「摘要已在進行中」錯誤。這是不同的?

app.component('myComponent', { 
    controller: function(){ 
     $scope.visible = false; 

     $rootScope.$on('someEvent', function(){ 
      $scope.visible = true; 
      $rootScope.$apply(); // why? 
     }); 
    } 
}); 
+0

沒有任何顯示錶明它是需要的。提供一個[mcve]我們不能猜測你的情況 – charlietfl

+2

$ rootScope。當你想手動運行摘要循環時需要$ apply(),所以如果任何事情發生在角度的上下文之外,那麼修改角度變量必須手動啓動摘要循環。一旦摘要循環正在運行,你試着應用它會給你那個錯誤 –

+0

我不認爲這是需要在這種情況下。 '$ scope。$ on'已經調用了摘要循環,所以函數內部的每一個變化都會被更新。 – Icycool

回答

3

$rootScope.$on註冊的回調是由兩種或$rootScope.$broadcast觸發$rootScope.$emit。如果您研究這些方法源代碼,您將看到這些方法本身不會觸發$digest週期(髒檢查)。這意味着$digest應該由調用$broadcast$emit的代碼觸發,或者在註冊爲$rootScope.$on的回調中觸發。

通常情況下,最好是假設觸發回調內部$digest循環,這意味着回撥電話應$apply包裹,如:

$rootScope.$apply($rootScope.$broadcast('event', data)); 

這是什麼角度最佳實踐suggest一致:

$ scope。$ apply()應該儘可能接近於異步事件綁定,如 。

0

我可以想像,如果你想支持從外部AngularJS世界事件$scope.$apply是必要的。看看並考慮如何支持來自AngularJS(ng-click)和jQuery(onClick)的事件的差異。

angular.module('app', []) 
 
    .controller('ctrl', function($scope) { 
 
    $scope.click = function() { 
 
     $scope.$emit('inside', { 
 
     message: 'from AngularJS world' 
 
     }) 
 
    } 
 
    }) 
 
    .directive('eventListener', function() { 
 
    return { 
 
     restrict: 'E', 
 
     controller: function($scope) { 
 
     $scope.message = 'listening' 
 

 
     // in AngularJS context - $apply will throw error that $digest is already running! 
 
     $scope.$on('inside', function(event, args) { 
 
      $scope.message = args.message 
 
     }) 
 

 
     // let to know AngularJS that something changes 
 
     $scope.$on('outside', function(event, args) { 
 
      $scope.$apply(function() { 
 
       $scope.message = args.message 
 
      }) // this is eqvivalent to: 
 
      /* 
 
      $scope.message = args.message 
 
      $scope.$apply() 
 
      */ 
 
     }) 
 
     }, 
 
     template: '<div>message: {{ message }}</div>' 
 
    } 
 
    }) 
 
    .directive('jQueryClick', function() { 
 
    return { 
 
     restrict: 'E', 
 
     link: function(scope, element) { 
 
     $(element).on('click', function() { 
 
      scope.$emit('outside', { 
 
      message: 'outside AngularJS' 
 
      }) 
 
     }) 
 
     }, 
 
     template: '<div><button click="click()">jQuery - onClick()!</button></div>', 
 
    } 
 
    })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 
<div ng-app="app"> 
 
    <div ng-controller="ctrl"> 
 
    <button ng-click="click()">AngularJS ng-click!</button> 
 
    </div> 
 
    <div> 
 
    <j-query-click></j-query-click> 
 
    </div> 
 
    <div> 
 
    <event-listener></event-listener> 
 
    </div> 
 
</div>

因爲這將是很難決定什麼是變化的根源以及應該如何被應用到$範圍我們可以將$從$上申請$發出部分。

angular.module('app', []) 
 
    .controller('ctrl', function($scope) { 
 
    $scope.click = function() { 
 
     $scope.$emit('message', { 
 
     message: 'from AngularJS world' 
 
     }) 
 
    } 
 
    }) 
 
    .directive('eventListener', function() { 
 
    return { 
 
     restrict: 'E', 
 
     controller: function($scope) { 
 
     $scope.message = 'listening' 
 

 
     /* 
 
     * We are goint to support internal and external message in the same way, 
 
     * we can simplify support for it 
 
     * 
 
     $scope.$on('inside', function(event, args) { 
 
      $scope.message = args.message 
 
     }) 
 

 
     $scope.$on('outside', function(event, args) { 
 
      $scope.message = args.message 
 
     }) 
 
     */ 
 

 
     $scope.$on('message', function(event, args) { 
 
      $scope.message = args.message 
 
     }) 
 
     }, 
 
     template: '<div>message: {{ message }}</div>' 
 
    } 
 
    }) 
 
    .directive('jQueryClick', function() { 
 
    return { 
 
     restrict: 'E', 
 
     link: function(scope, element) { 
 
     $(element).on('click', function() { 
 
      scope.$apply(scope.$emit('message', { 
 
      message: 'outside AngularJS' 
 
      })) 
 
     }) 
 
     }, 
 
     template: '<div><button click="click()">jQuery - onClick()!</button></div>', 
 
    } 
 
    })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 
<div ng-app="app"> 
 
    <div ng-controller="ctrl"> 
 
    <button ng-click="click()">AngularJS ng-click!</button> 
 
    </div> 
 
    <div> 
 
    <j-query-click></j-query-click> 
 
    </div> 
 
    <div> 
 
    <event-listener></event-listener> 
 
    </div> 
 
</div>

相關問題