4

I have a connection to a websocket server that pushes messages to my angularJS App. I receive those messages in a service and now I want to public this data on the gui.

angular.module("test", [])
   .value("DATA", [])
   .service("WSS", ["$rootScope", "DATA", function ($rootScope, DATA) {

       //initialise websocket here

       m_WebSocket.onmessage = function (msg) {
           $rootScope.$apply(function () {
               DATA = angular.fromJson(msg.data).slice();
           });

           console.debug(DATA); //gives me the expected result
       };
   }])
   .controller("CTRL", ["$scope", "DATA", function ($scope, DATA) {
       $scope.data = DATA;//wont update
   }]);

So, as far as I have understood angular I thought it must work this way but my DATA Array stays empty. What am I missing here?

1
  • A few things, try to very sparingly use $rootcope, there's almost always a better way. Also, you shouldn't be doing anything with a $scope of any kind within a service. Only controllers/directives access $scope. Commented Mar 2, 2015 at 14:22

1 Answer 1

4

The problem is that when you assign DATA = angular.fromJson(msg.data).slice(); it doesn't affect $scope.data = DATA; at all, because $scope.data and new DATA array in service are not connected, they point to different objects. We say that there is no reference between them. So it won't update in view also.

It's very easy to fix if you just change a property of the object instead of overriding object reference entirely:

angular.module("test", [])
    .value("DATA", {values: []})
    .service("WSS", ["$rootScope", "DATA", function ($rootScope, DATA) {

    //initialise websocket here

    m_WebSocket.onmessage = function (msg) {
        $rootScope.$apply(function () {
            DATA.values = angular.fromJson(msg.data).slice();
        });
    };
}])

.controller("CTRL", ["$scope", "DATA", function ($scope, DATA) {
    $scope.data = DATA;
}]);

And then in template you would use data.values instead of just data like you did before.

In this case $scope.data is an object which has property values. When new message comes from the server, the only thing that changes is property values of the DATA object. But in controller $scope.data points to the same object, hence Angular will be able to pick up chose new data.

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you very much, this seems to solve my problem :) But is it bad practice to use $rootScope for this case or what would be a better way to achive this?
You need to trigger digest anyway somehow. One way is to use $apply on the scope. So you have to use $rootScope, because you don't have controller scope anyway. Other option is to use $timeout service $timeout(function () { DATA.values = angular.fromJson(msg.data).slice(); });
Is there any disadvantage in using $timeout over $rootScope?
Well $timeout calls $rootScope.$apply internally, so.. The code is a bit cleaner, but still the fact is that you need to trigger digest and you don't have many options. I would continue using $rootScope.$apply.
Thanks, I'll go for it :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.