如何从AngularJS中观察窗口变量

How to Watch Window Variables from Within AngularJS

本文关键字:观察 窗口 变量 AngularJS      更新时间:2023-09-26

我有一组窗口变量,我想将它们绑定到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中观察窗口变量?

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

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

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

您可以使用angular中的一个简单钩子,在现有指令的作用域上简单地调用$digest。然后,使用函数返回窗口属性的当前值,而不是像当前那样观察变量值。这样,如果值是简单类型(字符串、数字)或被替换,您就不会丢失手表:

/*** 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。