1

我的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]);
  });
};

flash如果我运行此代码,我会在 websocket 连接上收到调试消息,但仅当我单击按钮 fe 或调用该$apply函数时,才会应用对数组的更改。后者导致“申请已在进行中”的错误。经过一些研究,我确信,调用 to$apply是没有必要的。

那么:如何以flash一种立即通知视图有关更改的方式更改数组?

4

2 回答 2

2

好吧,您确实需要$apply从 WebSocket 代码中调用。WebSocket 事件发生在 Angular 之外,所以它是必要的。如果您$apply导致消息摘要已经在处理中,是否有其他代码也发送“flash”消息?

我建议你把$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放在错误的位置,但有可能实现您的目标。

于 2013-10-28T09:53:04.123 回答
0

我在相关的so-post中找到了答案。所以我已经将调用包装$broadcast成一个$timeout.

$timeout(function () {
  $rootScope.$broadcast("flash", "websocket connected"); 
}, 50);

请发表评论如果您知道,为什么会这样!

于 2013-10-28T09:53:15.593 回答