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:
Is this the expected behavior of angular that my list does not automatically get updated if I do not use $rootScope.apply()
?
Why do I even need to wrap it in $rootScope.apply()
?
Is using $rootScope.apply()
the correct way to solve this?
Are there better alternatives to $rootScope.apply()
for this problem?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…