2016-11-22 2 views
3

この例では、ページ上でng-hideを使用して要素を更新するのに、$rootScope.$apply()が必要なのはなぜですか?

私の経験上、$scope.$apply()$scope.$watchに入れたときは、「ダイジェストはすでに進行中です」というエラーが表示されます。これは違うの?

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

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

何も表示されていないことが示唆されています。あなたの状況で推測することはできません – charlietfl

+2

$ rootScope。手動でダイジェストサイクルを実行する必要がある場合には$ apply()が必要です。角度のコンテキストから何かが発生して、 manualllyダイジェストサイクルを実行してください。ダイジェストサイクルが実行されていて、それを適用しようとすると、そのエラーが発生します。 –

+0

このケースでは必要ないと思います。 '$ scope。$ on'はすでにダイジェストサイクルを呼び出していますので、関数内のすべての変更はすでに更新されています。 – Icycool

答えて

3

コールバックは$rootScope.$broadcastまたは$rootScope.$emitのいずれかによってトリガされます。これらのメソッドのソースコードを調べると、これらのメソッドだけではサイクル(ダーティチェック)が発生しないことがわかります。つまり、$digestは、$broadcastまたは$emitを呼び出すコード、または$rootScope.$onで登録されたコールバックのいずれかでトリガーする必要があります。

通常、そのコールバックが$digestループ内でトリガされたと仮定すると良いでしょうし、それはのように、コールバックコールが$applyでラップする必要があることを意味します

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

これはどのような角度のベストプラクティスsuggestと一致している。

$ scope。$ apply()は、 として可能なasyncイベントバインディングに近いものとして発生する必要があります。

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>

これは、変更のソースであるかを決定するのは難しいだろうとどのようにそれが$スコープに適用されるべきである私たちは、$がに$ からを適用する移動することができたよう〜$ emit部分。 $rootScope.$onに登録

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>

関連する問題