角 - 的WebSocket和$ rootScope.apply() [英] Angular - Websocket and $rootScope.apply()

查看:180
本文介绍了角 - 的WebSocket和$ rootScope.apply()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在玩弄一个使用WebSocket的与后端通信的角度应用程序。我有一些麻烦角的数据绑定正常工作。

在下面,我创建了创建WebSocket连接服务的例子。如果WebSocket的收到一条消息,我只是把该消息为包含所有收到的消息的数组。

在我的控制器我的消息进行阵列结合的范围,然后使用 NG-重复全部列出来,我的局部视图。

服务:

 厂('为MyService,[功能(){  VAR wsUrl = angular.element(document.querySelector('#WS-URL'))VAL()。
  变种WS =新的WebSocket(wsUrl);  ws.onopen =功能(){
    的console.log(建立连接...);
  }
  ws.onmessage =函数(事件){
      Service.messages.push(Event.data中);
  }  变种服务= {};
  Service.messages = [];
  退换货服务;
}]);

控制器:

 控制器('MyCtrl1',['$范围,为MyService',函数($范围,为MyService){
  $ scope.messages = MyService.messages;
}])

部分:

 < UL>
  <李NG重复=味精消息>
      {{味精}}
  < /李>
< / UL>

然而,这并不正常工作。当收到一个新的消息,并被推入数组,应显示的所有消息没有更新该列表。我预期,因为角度双向数据绑定的更新。

我已经找到了一个解决方案,通过包装的消息推到一个呼叫 $ rootScope.apply()中的服务工作:

  ws.onmessage =函数(事件){
  $ rootScope。$应用(函数(){
    Service.messages.push(Event.data中);
  });
}

我的问题是:


  1. 那是我的列表不会自动得到,如果我不使用更新的角度这个预期的行为 $ rootScope.apply()


  2. 为什么我甚至需要把它包在 $ rootScope.apply()


  3. 中使用 $ rootScope.apply()来解决这个问题的正确方法是什么?


  4. 在那里 $ rootScope.apply()更好的选择这个问题?



解决方案

  1. 是的,AngularJS的绑定回合制,他们只对某些DOM事件并呼吁火灾 $适用 / $摘要。还有像 $ HTTP $超时是为你做包装,但是的那之外的任何要求或者电话 $适用 $消化


  2. 您需要让AngularJS知道你已经更改了绑定到一个范围,因此它可以更新视图的变量。还有其他的方法来做到这一点,虽然。


  3. 这取决于你所需要的。在 $包住code适用(),AngularJS包装内部angularjs记录和异常处理您的code,当它已经结束了,它传播 $摘要所有控制器的作用域。在大多数情况下,在包装 $适用()是最好的方法,它使更多的门打开角将来的功能,你可能最终使用。它是正确的方法是什么?阅读下文。


  4. 如果你不使用角度的错​​误处理,你知道你的变化不应该传播到其他范围(根,控制器或指令),你需要优化性能,你可以调用 $消化上专门控制器的 $范围。这样脏检查不传播。否则,如果你不希望错误被角被抓住了,但需要脏​​检查传播到其他控制器/指令/ rootScope,就可以了,而不是使用$包装适用,只调用 $ rootScope。$适用()后所做的更改。


更多参考:
$适用 VS $摘要

I'm currently playing around with an angular app that uses a websocket to communicate with the backend. I've had some trouble getting angular's data binding working correctly.

In the example below I've created a service which creates the websocket connection. If the websocket receives a message I just push that message into an array which contains all of the received messages.

In my controller I bind that array of messages to the scope and then use ng-repeat to list them all in my partial view.

Service:

factory('MyService', [function() {

  var wsUrl = angular.element(document.querySelector('#ws-url')).val();
  var ws = new WebSocket(wsUrl);

  ws.onopen = function() {
    console.log("connection established ...");
  }
  ws.onmessage = function(event) {
      Service.messages.push(event.data);
  }   

  var Service = {};
  Service.messages = [];
  return Service;
}]);

Controller:

controller('MyCtrl1', ['$scope', 'MyService', function($scope, MyService) {
  $scope.messages = MyService.messages;
}])

Partial:

<ul>
  <li ng-repeat="msg in messages">
      {{msg}} 
  </li>
</ul>

This however does not work correctly. When a new message is received and pushed into the array, the list that should display all messages does not get updated. I expected it to be updated because of angular two way data binding.

I've found one solution that works by wrapping the pushing of the message into a call to $rootScope.apply() in the service:

ws.onmessage = function(event) {
  $rootScope.$apply(function() {
    Service.messages.push(event.data);
  });
}  

My questions are:

  1. Is this the expected behavior of angular that my list does not automatically get updated if I do not use $rootScope.apply() ?

  2. Why do I even need to wrap it in $rootScope.apply()?

  3. Is using $rootScope.apply() the correct way to solve this?

  4. Are there better alternatives to $rootScope.apply() for this problem?

解决方案

  1. Yes, AngularJS's bindings are "turn-based", they only fire on certain DOM events and on calls to $apply/$digest. There are some useful services like $http and $timeout that do the wrapping for you, but anything outside of that requires calls to either $apply or $digest.

  2. You need to let AngularJS know you've changed a variable that's bound to a scope so it can update the view. There are other ways to do this though.

  3. It depends on what you need. When wrap your code in $apply(), AngularJS wraps your code in internal angularjs logging and exception handling, and when it's over, it propagates $digest to all of your controller's scopes. In most cases, wrapping in $apply() is the best way, it leaves more doors open for future features of angular you might end up to using. Is it the correct way? Read below.

  4. If you don't use Angular's error handling, and you know your changes shouldn't propagate to any other scopes (root, controllers or directives), and you need to optimize for performance, you could call $digest on specifically your controller's $scope. This way the dirty-checking doesn't propagate. Otherwise, if you don't want errors to be caught by Angular, but need the dirty-checking to propagate to other controllers/directives/rootScope, you can, instead of wrapping with $apply, just calling $rootScope.$apply() after you made your changes.

Further reference: $apply vs $digest

这篇关于角 - 的WebSocket和$ rootScope.apply()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆