如何在AngularJS中观察窗口变量

时间:2015-11-13 21:45:14

标签: javascript angularjs

我有一组窗口变量,我想绑定到AngularJS中的范围变量。

到目前为止,这是我的代码,但它不起作用:

        .directive('watchGlobals', function() {
            return {
                link: function(scope, element, attrs) {
                        var watchGlobals = attrs.watchGlobals.split(',');
                        for (var i = 0; i < watchGlobals.length; i++) {
                            scope[watchGlobals[i]] = window[watchGlobals[i]];
                        }
                }
            }
        });

这样做的最佳方法是什么?我试图避免使用setInterval。我想在更新窗口变量时更新范围。有没有办法可以在AngularJS中观察窗口变量?

2 个答案:

答案 0 :(得分:2)

使用简单的js pubsub(例如PubSubJs),您可以在角度内订阅服务。另一个应用程序应该通过pubsub发布,这将调用服务中的调用。该服务将更新角度应用程序。

angular.factory('connectService', ['$rootScope', function($rootScope) {

    var token = PubSub.subscribe( 'TOPIC_NAME', function(msg, data) {
        $rootScope.$apply(function() {
            $rootScope.$broadcast('TOPIC_NAME', { msg: msg, data: data });
        });
    });

}]);

从其他应用中,您现在可以发布数据:

PubSub.publish( 'MY TOPIC', 'hello world!' );

现在,只要您想要以角度使用方式获取数据:

$scope.$on('TOPIC_NAME', function(data) {
    console.log(data.msg, data.data); // do whatever you want to do with the data
});

答案 1 :(得分:1)

正如评论所说,有很多方法可以做到这一点,推送数据可能比听取数据更好。

您可以使用简单的钩子角度来简单地调用现有指令范围内的$digest。然后,不要像当前那样观察变量值,而是使用函数返回window属性的当前值。这样,如果值是简单类型(字符串,数字)或被替换,则不会丢失监视:

/*** angular code ***/

angular.module('myApp', [])

    .controller('ctrl', function() {})

    // inject the standard angular $window service (really just the window object)
    .directive('watchGlobals', function($window) {
        return {
            link: function(scope, element, attrs) {

                // add a method to the raw DOM element that JS can call to update the scope
                element[0].externalUpdate = function() {
                    scope.$digest();
                };

                var watchGlobals = attrs.watchGlobals.split(',');
                // loop as before, but use an IIFE to isolate the variable name
                for (var i = 0; i < watchGlobals.length; i++) {
                    (function(variable) {
                        scope.$watch(function() { return $window[variable]; }, // use a function
                                     function(newVal) { scope[variable] = newVal; }); // update scope
                    })(watchGlobals[i]);
                }
            }
        }
    });

/*** JS code ***/

// global function to update angular scope
function updateAngular() {
    // find the directive element and call it's externalUpdate() function
    // this is the only "bit in the middle" of the 2 apps
    document.getElementById('angular-hook').externalUpdate();

    // alternative option, but breaks with $compileProvider.debugInfoEnabled(false)
    //angular.element(document.getElementById('angular-hook')).scope().$digest();
}

function setValueX() {
    window.xVal = document.getElementById('valX').value;
    updateAngular();
}

function setValueY() {
    window.yVal = document.getElementById('valY').value;
    updateAngular();
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<h2>Angular</h2>
<div ng-app="myApp">
    <div ng-controller="ctrl">
        <div id="angular-hook" watch-globals="xVal,yVal"></div>
        <p>x: {{xVal}}</p>
        <p>y: {{yVal}}</p>
    </div>
</div>

<h2>JS</h2>
<p>X: <input type="text" id="valX" /> <button onclick="setValueX()">Set</button></p>
<p>Y: <input type="text" id="valY" /> <button onclick="setValueY()">Set</button></p>

UPDATE:scope().$digest()调用更改为DOM元素函数以解决debugInfo问题。