1

I need a global application wise web-socket, which can be used by all of my controller in app.

The following code describes the my use-case where I am creating a factory to share a singleton websocket object. The interface provided are allows the controllers to send the data over socket and attach listener for incoming messages.

The problem with the following code is that I am able to send the data on socket as expected, but not able to receive data when it comes over the socket.

I have read several angular digest related solutions, but they are not working for me.

angular
  .module('myApp', [])
  .factory('socket', function() {
    var socketStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
    var socket = new WebSocket("ws://localhost:7070/ws");
    socket.onopen = function(event) {
      socket.send("hello");
    };

    socket.addEventListener('message', function(event) {
      // I am able to see this so, it is confirmed that server is sending the data
      console.log(event);
    });

    return {
      emit: function (data) {
        socket.send(JSON.stringify(data));
      },
      on: function(callback) {
        socket.addEventListener('message', callback);
      },
      getStatus: function() {
        var status = socket.readyState;
        return socketStates[status]
      }
    };
  })
  .controller('MyController', function(socket){
    var myctl = this;

    //This works
    socket.emit({type : "register", name: producer});

    //This doesn't work
    socket.on(function(event) {
      console.log(event);
    });
  });

$rootScope.$apply(socket.addEventListener('message', callback));

instead of

socket.addEventListener('message', callback);

throws the following error

vendor.js:5 Error: [$rootScope:inprog] $digest already in progress(…)(anonymous function)

10
  • Should your eventListener be reading 'onmessage'? Commented Apr 18, 2017 at 13:41
  • couldn't understand your question, yes the eventListener should be fired on onmessage Commented Apr 18, 2017 at 13:47
  • Try swapping emit and socket.on and ensure your server is sending any data Commented Apr 18, 2017 at 13:47
  • I believe the message listener doesn't exist? The onmessage event listener is what is documented on the socket docs? Commented Apr 18, 2017 at 13:50
  • @Oskar I am sure the server is sending the data, check the code I have edited the code. Commented Apr 18, 2017 at 13:54

2 Answers 2

2

The digest process is already in progress you have to check the $$phase and wrap your code with if statement:

if (!$scope.$$phase) {
  $rootScope.$apply(socket.addEventListener('message', callback));
} else {
  socket.addEventListener('message', callback);  
}

For more check: AngularJS : Prevent error $digest already in progress when calling $scope.$apply()

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

8 Comments

can we have $scope inside factory ?
In theory you can, but I wouldn't recommend that, if you use $rootScope in your factory consider refactoring your code. $$phase probably works with $rootScope as well
It's working now, and don't understand how, becuase my code is going in to still else part. And more thing why (!$scope.$$phase) is considered as anti-pattern ?
@bruce_wayne I think it's prone to error, because it can create race conditions and fire many unnecessary $apply / $digest phases one after another
what's the better way to do it ?
|
0

Your socket.on() event is running digest cycle which is conflicting with current digest cycle.

you can use setTimeut() to solve this problem

setTimeout(function(){ 
       socket.on(function(event) {
          console.log(event);
      }); 
});

Comments

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.