1

私のAngularJSアプリには、次の単純化された動作があります。

というファクトリを持つサービスモジュールを作成しましたserver。このserverモジュールは、websocket サーバーへの通信を処理します。この websocket 接続内でイベントが発生したときに、点滅するメッセージを my 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 接続でデバッグ メッセージが表示されますが、flash配列への変更は、fe ボタンをクリックするか関数を呼び出した場合にのみ適用されます$apply。後者の場合、「適用がすでに進行中です」というエラーが発生します。いくつかの調査の後、への呼び出しは必要ないと確信しています$apply

flashでは、変更についてすぐにビューに通知する方法で配列を変更するにはどうすればよいでしょうか?

4

2 に答える 2

2

$applyWebSocket コードから呼び出す必要があります。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);
  }
};

次に、「フラッシュ」イベントを受け取ったら、次のようにします。

$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 に答える