Angular: Можно ли наблюдать за глобальной переменной (т. Е. Вне области видимости)?

Позвольте мне начать с того, что то, что я пытаюсь сделать, вероятно, не считается хорошей практикой. Тем не менее, мне нужно сделать что-то подобное, чтобы перенести большое веб-приложение на AngularJ небольшими пошаговыми шагами.

Я пытался делать

 $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();
});

Я присуждаю баллы Андерсу, хотя и пойду с другим решением, поскольку его решение правильно решает поставленную задачу.

1 ответ

Решение

Проблема здесь, вероятно, в том, что вы модифицируете myVar из-за пределов углового мира. Angular не запускает циклы дайджеста / грязные проверки все время, только когда что-то происходит в приложении, которое должно вызвать дайджест, например, события DOM, о которых знает Angular. Так что даже если 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>
Другие вопросы по тегам