2016-11-22 3 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() требуется, если вы хотите вручную запустить цикл дайджеста, поэтому, если что-то происходит из контекста угловой, который изменяет угловые переменные, которые вы должны manuallly запускать цикл дайджест. Когда цикл дайджест запущен, и попробуйте применить его, вы получите u, что ошибка –

+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() должен происходить как можно ближе к привязке события async как возможно .

0

Я могу себе представить, что $scope.$apply необходимо, если вы хотите поддерживать события из-за пределов AngularJS мира. Взгляните и рассмотрите различия в том, как поддерживать события из 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>

Смежные вопросы