Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Improve this AngularJS factory to use with socket.io

I want to use socket.io in AngularJS. I found the following factory:

app.factory('socket', function ($rootScope) {     var socket = io.connect();     return {         on: function (eventName, callback) {             socket.on(eventName, function () {                 var args = arguments;                 $rootScope.$apply(function () {                     callback.apply(socket, args);                 });             });         },         emit: function (eventName, data, callback) {             socket.emit(eventName, data, function () {                 var args = arguments;                 $rootScope.$apply(function () {                     if (callback) {                         callback.apply(socket, args);                     }                 });             })         }     }; 

and it is used in the controller like:

function MyCtrl($scope, socket) {     socket.on('message', function(data) {         ...     }); }; 

the problem is that each time the controller is visited another listener is added, so when a message is received it is handled multiple times.

what can be a better strategy to integrate socket.io with AngularJS ?

EDIT: I know that I can return nothing in the factory and do the listening there, then use $rootScope.$broadcast and $scope.$on in the controllers, but it doesn't look like a good solution.

EDIT2: added to the factory

init: function() {             socket.removeAllListeners(); } 

and call it at the beginning of each controller that use socket.io.

still doesn't feel like the best solution.

like image 792
Gal Ben-Haim Avatar asked Jan 17 '13 22:01

Gal Ben-Haim


People also ask

How do I use NGX-socket-Io in angular?

ngx-socket-io is an Angular wrapper over Socket.IO client libraries. Then, use the @angular/cli command to generate a document model, a document-list component, a document component, and a document service: ng generate class models/ document --type = model ng generate component components/ document-list

How do I check if my WebSocket server is working with angular?

When you run this you should see our websocket server print out something like the below output. It first starts on port 5000, when we then open up our Angular client you should then see it log user connected and then every time we send a message from our client you see the contents of that message being outputted below.

How do I install the angular CLI on Linux?

Open a new terminal window and navigate to the project directory. Run the following commands to install the Angular CLI as a devDependency: Now, use the @angular/cli command to create a new Angular project, with no Angular Routing and with SCSS for styling: ngx-socket-io is an Angular wrapper over Socket.IO client libraries.

Where can I find the source code for this angular 4 Tutorial?

The full source code for this tutorial can be found here: elliotforbes/angular-socket-io-example In this tutorial we are going to be looking at how we can build a realtime application using both Angular 4 and the Socket.io library.


2 Answers

Remove the socket listeners whenever the controller is destroyed. You will need to bind the $destroy event like this:

function MyCtrl($scope, socket) {     socket.on('message', function(data) {         ...     });      $scope.$on('$destroy', function (event) {         socket.removeAllListeners();         // or something like         // socket.removeListener(this);     }); }; 

For more information check the angularjs documentation.

like image 140
bmleite Avatar answered Sep 28 '22 07:09

bmleite


You might be able to handle this with a minimal amount of work by wrapping up a Scope and watching for $destroy to be broadcast, and when it is, only removing from the socket the listeners that were added in the context of that Scope. Be warned: what follows hasn't been tested--I'd treat it more like pseudocode than actual code. :)

// A ScopedSocket is an object that provides `on` and `emit` methods, // but keeps track of all listeners it registers on the socket. // A call to `removeAllListeners` will remove all listeners on the // socket that were created via this particular instance of ScopedSocket.  var ScopedSocket = function(socket, $rootScope) {   this.socket = socket;   this.$rootScope = $rootScope;   this.listeners = []; };  ScopedSocket.prototype.removeAllListeners = function() {   // Remove each of the stored listeners   for(var i = 0; i < this.listeners.length; i++) {     var details = this.listeners[i];     this.socket.removeListener(details.event, details.fn);   }; };  ScopedSocket.prototype.on = function(event, callback) {   var socket = this.socket;   var $rootScope = this.$rootScope;    var wrappedCallback = function() {     var args = arguments;     $rootScope.$apply(function() {       callback.apply(socket, args);     });   };    // Store the event name and callback so we can remove it later   this.listeners.push({event: event, fn: wrappedCallback});    socket.on(event, wrappedCallback); };  ScopedSocket.prototype.emit = function(event, data, callback) {   var socket = this.socket;   var $rootScope = this.$rootScope;    socket.emit(event, data, function() {     var args = arguments;     $rootScope.$apply(function() {       if (callback) {         callback.apply(socket, args);       }     });   }); };  app.factory('Socket', function($rootScope) {   var socket = io.connect();    // When injected into controllers, etc., Socket is a function   // that takes a Scope and returns a ScopedSocket wrapping the   // global Socket.IO `socket` object. When the scope is destroyed,   // it will call `removeAllListeners` on that ScopedSocket.   return function(scope) {     var scopedSocket = new ScopedSocket(socket, $rootScope);     scope.$on('$destroy', function() {       scopedSocket.removeAllListeners();     });     return scopedSocket;   }; });  function MyController($scope, Socket) {   var socket = Socket($scope);    socket.on('message', function(data) {      ...   }); }; 
like image 20
Michelle Tilley Avatar answered Sep 28 '22 08:09

Michelle Tilley