首先让我说我想做的事情可能不是好习惯。但是,我需要做这样的事情,以便以小的增量步骤将大型Web应用程序迁移到AngularJs。
我试过
$scope.$watch(function () { return myVar; }, function (n, old) {
alert(n + ' ' + old);
});
其中myVar是全局变量(在窗口上定义)
然后从控制台更改myVar。 但它只在首次设置观察者时触发。
如果我从控制器中更新myVar,它会起作用(请参阅http://jsfiddle.net/rasmusvhansen/vsDXz/3/,但如果从某些旧版javascript更新,则无效
有没有办法实现这个目标?
更新 如果遗留代码完全不受限制,我喜欢Anders的回答。但是,目前我正在研究这种似乎有用的方法,并且不包括每秒发射一次的计时器:
// In legacy code when changing stuff
$('.angular-component').each(function () {
$(this).scope().$broadcast('changed');
});
// In angular
$scope.$on('changed', function () {
$scope.reactToChange();
});
即使我会采用其他解决方案,我也会向Anders授予积分,因为他的解决方案正确地解决了所述问题。
答案 0 :(得分:12)
这里的问题可能是您正在从Angular世界之外修改myVar
。 Angular不会一直运行摘要周期/脏检查,只有在应该触发摘要的应用程序中发生事件时,例如Angular知道的DOM事件。因此,即使myVar
发生了变化,Angular也没有理由开始新的摘要周期,因为没有发生任何事情(至少Angular知道这一点)。
因此,为了激活您的手表,您需要在更改myVar
时强制Angular运行摘要。但这会有点麻烦,我认为你最好创建一个全局可观察对象,如下所示:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
<script>
// Outside of Angular
window.myVar = {prop: "value1"};
var myVarWatch = (function() {
var watches = {};
return {
watch: function(callback) {
var id = Math.random().toString();
watches[id] = callback;
// Return a function that removes the listener
return function() {
watches[id] = null;
delete watches[id];
}
},
trigger: function() {
for (var k in watches) {
watches[k](window.myVar);
}
}
}
})();
setTimeout(function() {
window.myVar.prop = "new value";
myVarWatch.trigger();
}, 1000);
// Inside of Angular
angular.module('myApp', []).controller('Ctrl', function($scope) {
var unbind = myVarWatch.watch(function(newVal) {
console.log("the value changed!", newVal);
});
// Unbind the listener when the scope is destroyed
$scope.$on('$destroy', unbind);
});
</script>
</head>
<body ng-controller="Ctrl">
</body>
</html>