javascript - ejemplos - $ scope. $ watch no se activa con cada cambio
angularjs tutorial (5)
Esto sucede porque el reloj solo se activará si el valor se cambia "entre" los bucles de resumen.
Su función está cambiando el valor del mensaje en el alcance en la misma función. Esto se ejecutará en el mismo bucle de resumen. Cuando angular se mueve al siguiente bucle, solo verá el último valor cambiado, que en su caso será hi22
.
Here''s un gran artículo que aclara este comportamiento.
Estoy usando angularJS 1.4.8, ayer noté que el $ scope. $ Watch no se activa en cada cambio que causó un error en mi aplicación.
¿Hay una manera de forzarlo a trabajar en cada cambio inmediatamente? Al igual que en este código, en cada cambio en el mensaje quiero que se active la función en reloj:
(function(){
angular.module(''myApp'', [])
.controller(''myAppController'', myAppController)
function myAppController($scope){
console.log(''controller loading !'');
$scope.message = ''message1'';
$scope.$watch(''message'', function(newMessage){
console.log(''newMessage'', newMessage)
});
function changeMessage(){
$scope.message=''hi'';
$scope.message=''hi12'';
}
changeMessage();
}
})();
La consola imprimirá:
controller loading !
newMessage hi22
enlace Plunker https://plnkr.co/edit/SA1AcIVwr04uIUQFixAO?p=preview
edición: realmente me gustaría saber si hay alguna otra forma que no sea ajustar el cambio con el tiempo de espera y usar el ámbito de aplicación, en mi código original iv''e varios lugares donde cambio la propiedad del alcance y me gustaría evitar usar esto cada cambio .
No es necesario envolver changeMessage en setTimeout y $ apply al mismo tiempo. Si necesita saltarse algún tiempo antes de la ejecución, solo use:
function changeMessage(){
$timeout(function(){
$scope.message = ''message'';
}/* or add time here, doesn''t matter */);
}
O solo:
function changeMessage(){
$scope.message = ''message'';
$scope.$apply();
}
Ambos métodos llaman $rootScope.$digest
al final. Aquí hay más información: codingeek.com/angularjs/…
Si cambia el valor en el mismo ciclo de resumen, el observador no se activa y se toma el último valor. Cuando ejecutamos $timeout
, $scope.message
valor de $scope.message
en el siguiente ciclo de resumen y el observador lo $scope.message
como se espera.
Echa un vistazo a la prueba simple:
$scope.$watch(function(){
console.log(''trigger'');
return $scope.message;
},
function(newMessage){
console.log(''newMessage'', newMessage)
});
function changeMessage(){
$scope.message=''hi'';
$timeout(function(){
$scope.message=''hi12'';
});
}
Salida:
controller loading !
trigger
newMessage hi
trigger
trigger
newMessage hi12
trigger
actualice la función changeMessage para que use $ scope. $ apply, que garantizará que sus cambios se reflejen y que Angular esté al tanto de sus cambios en la variable.
changeMessage() {
setTimeout(function () {
$scope.$apply(function () {
$scope.message = "Timeout called!";
});
}, 2000);
}
$watch()
solo activa entre cada $digest()
.
Explicación detallada sobre el $apply()
y $digest()
En su caso, sigue actualizando el $scope.message
en el ciclo $digest()
actual.
Puede cambiar eso aplicando cada nuevo valor al $scope
usando $apply()
. Como escribió @Ajinkya. El único problema, con la configuración de 2000ms como tiempo de espera, no siempre garantiza que se ejecute después del $digest()
. Además de eso, Angular tiene una función de tiempo de espera de compilación. Vea abajo.
(function(){
angular.module(''myApp'', [])
.controller(''myAppController'', myAppController)
function myAppController($scope, $timeout){
console.log(''controller loading !'');
$scope.message = ''message1'';
$scope.$watch(''message'', function(newMessage){
console.log(''newMessage'', newMessage)
});
function changeMessage(){
setTimeout(function () {
$scope.$apply(function () {
$scope.message=''hi12'';
});
}, 2000);
}
changeMessage();
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myAppController"></div>
Solución
La mejor manera sería llamar a la función build in $timeout
, sin configurar el tiempo en milisegundos.
De esta manera, angular siempre garantiza que el $timeout
se ejecute después del último $digest()
. Además de eso. No tiene que usar $scope.$apply()
. Debido a que $timeout
allready ejecuta $digest()
, donde $scope.$apply()
$diggest()
invoca manualmente un nuevo $diggest()
.
(function(){
angular.module(''myApp'', [])
.controller(''myAppController'', myAppController)
function myAppController($scope, $timeout){
console.log(''controller loading !'');
$scope.message = ''message1'';
$scope.$watch(''message'', function(newMessage){
console.log(''newMessage'', newMessage)
});
function changeMessage(){
$timeout(function () {
$scope.message=''hi12'';
});
}
changeMessage();
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myAppController"></div>