Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js + AngularJS + Socket.io : pushed data not available in the controller

I've setup my Node server to push out some data at random intervals, and the data is getting to the client/browser; however, I can't figure out how to access it in my app's controller.

#node.js file: /server.js (truncated for brevity)

var http    = require('http').createServer(handler),//refers to handler()
    fs      = require('fs'),
    io      = require('socket.io').listen(http);
http.listen(8000);

…

io.sockets.on('connection', function (socket) {
    /* DUMMY CODE: this generates fake alerts at random intervals */
    (function loop() {
        var rand = Math…;
        …
        setTimeout(function(){
            …
            var alert = { … };

            socket.emit('alert', {
                "alert": alert
            });//socket.emit()

            loop();
        }, rand);
    }());
});//io.sockets.on()

When I log alert to Terminal, it looks like this:

alert: {
    id: 258,
    lat:    -95.20933,
    long:   37.027676,
    neighbourhood: "Downtown",
    time:   //stringified js timestamp
}

And arguments from below contains the data I want (basically same as alert).

# /app/js/services.js

angular.module( 'BAR.services' , [])
.factory('socketio', function($rootScope){

    var socket = io.connect();
    return {
        on: function(event, callback) {
            socket.on(event, function(){
                //console.log(arguments);
                $rootScope.$apply(function(){
                    callback.apply(socket, arguments);
                });//$rootScope.$apply()
            });//socket.on()
        },//on
        emit: function(event, data, callback) {
            socket.emit(event, data, function(){
                //console.log(arguments);
                $rootScope.$apply(function(){
                    if (callback) callback.apply(socket, arguments);
                });//$rootScope.$apply()
            });//socket.emit()
        },//emit
        disconnect: function() {
            socket.disconnect();
        }
    }//return

});// AlertServices

However, I can't figure out how to access the data from arguments in my controller:

# /app/js/controllers.js

function Alerts( $scope , socketio ) {

    socketio.on('alert', function(data) {
        console.log(data);      /* I expect this to be the data I want */
        $scope.alert = data.alert;
    });

    $scope.disconnect = function(){
        socketio.disconnect();
    }

}
Alerts.$inject = ['$scope','socketio'];

When I log data to the browser's console here in the controller, I get an enormous object that seems to be the parent of $scope; and data.alert is undefined. I also tried to specify a second parameter like this socketio.on('alert', function( data , args ) thinking it might be arguments (since callback.apply( … ) in services has 2), but when I did and logged it to console, args returned undefined.

Btw, I based this on a tutorial by an AngularJS intern. Different pieces had the same names, so I had a bit trouble figuring out what each the different peices did (also it was not helpful that it was in Jade).

What I really want to do is update a binding in my view with the data from alert.

like image 509
Jakob Jingleheimer Avatar asked Nov 27 '12 01:11

Jakob Jingleheimer


1 Answers

In your on and emit functions, you're using:

socket.on(event, function() {
  $rootScope.$apply(function() {
    callback.apply(socket, arguments);
  });
});

but in the original version of this from the tutorial, it says:

socket.on(eventName, function() {  
  var args = arguments;
  $rootScope.$apply(function () {
    callback.apply(socket, args);
  });
});

The var args = arguments is important, as it sets args to the arguments passed to the callback to socket.on (which is the data you're looking for). Without this step, when you actually use arguments, it resolves to the arguments passed into the callback to $rootScope.$apply (which is an Angular scope according to the documentation, explaining why you get the console output you do).

The solution would be to capture the arguments outside of the call to $apply and pass those into your callback:

socket.on(event, function() {
  var args = arguments;
  $rootScope.$apply(function() {
    callback.apply(socket, args);
  });
});
like image 55
Michelle Tilley Avatar answered Nov 09 '22 00:11

Michelle Tilley