我的 AngularJS 应用程序具有以下简化行为:
我创建了一个名为server
的工厂的服务模块。这个server
模块处理我与websocket服务器的通信。当此websocket连接中发生事件时,我想在MainController
中显示一条闪烁的消息。
我的服务:
return function init() {
ws = new WebSocket(...);
ws.onopen(function () {
$rootScope.$broadcast("flash", "websocket connected");
});
};
我的观点:
<article ng-controller=MainController ng-init=init()>
<section ng-show="flash.length > 0">
<p ng-repeat="message in flash">
{{ message }}
</p>
<section>
<section ng-view>
...
</article>
我的控制器:
function MainController ($rootScope, $scope, server) {
$scope.init = function () {
$scope.flash = [];
server.init();
};
$scope.on("flash", function (event, flash) {
$scope.flash.push(flash);
// $scope.$apply("$scope.flash"); <-- if I uncomment this line, I get the error...
console.debug($scope.flash[$scope.flash.length -1]);
});
};
如果我运行此代码,我会在websocket连接上获得调试消息,但是如果我单击按钮f.e,则仅应用对flash
数组的更改。或者如果我调用$apply
函数。
后者导致“应用已在进行中”的错误。经过一些研究,我确信,调用$apply
是没有必要的。
那么:如何以一种立即通知视图变化的方式改变flash
数组?
答案 0 :(得分:2)
嗯,您需要从WebSocket代码中调用$apply
。 WebSocket事件发生在Angular之外,所以这是必要的。如果您的$apply
导致摘要已在进行中,那么其他一些代码是否也可以发送“闪存”消息?
我建议您将$apply
调用放入WebSocket代码中:
return function init() {
ws = new WebSocket(...);
ws.onopen(function () {
$rootScope.$apply(function() {
$rootScope.$broadcast("flash", "websocket connected");
});
});
};
<强>附加强>
如果你真的需要将$apply
放在控制器中(我不建议这样做),那么你可以试试“安全应用”模式:
$scope.$safeApply = function (fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if (fn && (typeof (fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
然后,当您收到“flash”事件时,您可以这样做:
$scope.$safeApply(function() {
$scope.flash.push(flash);
});
同样,我认为这种方法将$apply
的知识放在了错误的地方,但是有可能实现你的目标。
答案 1 :(得分:0)
我在相关so-post中找到了答案。
所以我将$broadcast
的电话打包成$timeout
。
$timeout(function () {
$rootScope.$broadcast("flash", "websocket connected");
}, 50);
请发表评论如果您知道,为什么会这样?