11

首先让我说我正在尝试做的事情可能不被认为是好的做法。但是,我需要做这样的事情,以便以小的增量步骤将大型 Web 应用程序迁移到 AngularJs。

我试着做

 $scope.$watch(function () { return myVar; }, function (n, old) {
                    alert(n + ' ' + old);
                });

其中 myVar 是一个全局变量(在窗口中定义)

然后从控制台更改 myVar 。但它只在第一次设置观察者时触发。

如果我从控制器内更新 myVar (请参阅http://jsfiddle.net/rasmusvhansen/vsDXz/3/,但如果它是从某些旧版 javascript 更新的则不会)

有什么办法可以做到这一点?

更新 如果遗留代码完全不受限制,我喜欢安德斯的回答。但是,目前我正在研究这种似乎有效的方法,并且不包括每秒触发的计时器:

// In legacy code when changing stuff    
$('.angular-component').each(function () {
        $(this).scope().$broadcast('changed');
});

// In angular
$scope.$on('changed', function () {
    $scope.reactToChange();
});

即使我会采用另一种解决方案,我也会给安德斯加分,因为他的解决方案正确地解决了所述问题。

4

1 回答 1

12

这里的问题可能是您正在myVar从 Angular 世界之外进行修改。Angular 不会一直运行摘要循环/脏检查,只有当应用程序中发生应该触发摘要的事情时,例如 Angular 知道的 DOM 事件。因此,即使myVar发生了变化,Angular 也没有理由开始新的摘要循环,因为什么都没有发生(至少 Angular 知道)。

因此,为了触发您的手表,您需要在更改时强制 Angular 运行摘要myVar。但这有点麻烦,我认为您最好创建一个全局可观察对象,如下所示:

<!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>
于 2013-03-08T13:25:02.213 回答