0

I am trying to add socket.io to my angularjs project. My reference is http://www.html5rocks.com/en/tutorials/frameworks/angular-websockets/?redirect_from_locale=zh#disqus_thread. I am trying to modify it as below:

About the socket.io server: app.js:

var express = require('express');
var app = module.exports = express();

var server = require('http').createServer(app);

// Hook Socket.io into Express
var io = require('socket.io').listen(server);

// Socket.io Communication

var socket = require('./scripts/socket.js');
io.sockets.on('connection', socket);

// Start server at http://127.0.0.1:3000

server.listen(3000, function() {
console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});

scripts/socket.js:

// Keep track of which names are used so that there are no duplicates
var userNames = (function () {
  var names = {};

  var claim = function (name) {
    if (!name || names[name]) {
      return false;
    } else {
      names[name] = true;
      return true;
    }
  };

  // find the lowest unused "guest" name and claim it
  var getGuestName = function () {
    var name,
      nextUserId = 1;

    do {
      name = 'Guest ' + nextUserId;
      nextUserId += 1;
    } while (!claim(name));

    return name;
  };

  // serialize claimed names as an array
  var get = function () {
    var res = [];
    for (user in names) {
      res.push(user);
    }

    return res;
  };

  var free = function (name) {
    if (names[name]) {
      delete names[name];
    }
  };

  return {
    claim: claim,
    free: free,
    get: get,
    getGuestName: getGuestName
  };
}());

// export function for listening to the socket
module.exports = function (socket) {
  var name = userNames.getGuestName();

  // send the new user their name and a list of users
  socket.emit('init', {
    name: name,
    users: userNames.get()
  });

  // notify other clients that a new user has joined
  socket.broadcast.emit('user:join', {
    name: name
  });

  // broadcast a user's message to other users
  socket.on('send:message', function (data) {
    socket.broadcast.emit('send:message', {
      user: name,
      text: data.message
    });
  });

  // validate a user's name change, and broadcast it on success
  socket.on('change:name', function (data, fn) {
    if (userNames.claim(data.name)) {
      var oldName = name;
      userNames.free(oldName);

      name = data.name;

      socket.broadcast.emit('change:name', {
        oldName: oldName,
        newName: name
      });

      fn(true);
    } else {
      fn(false);
    }
  });

  // clean up when a user leaves, and broadcast it to other users
  socket.on('disconnect', function () {
    socket.broadcast.emit('user:left', {
      name: name
    });
    userNames.free(name);
  });
};

These are all the files for socket.io. After node app.js, it displays "Express server listening on port 3000 in development mode"


The angular part is modified from the angular seed: https://github.com/angular/angular-seed index.html:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <meta charset="UTF-8">
  <title>Angular Socket.io IM Demo App</title>
  <link rel="stylesheet" href="css/app.css"></head>
<body>
  <h1>Angular Socket.io IM Demo App</h1>
  <div ng-controller="AppCtrl">
    <div class="col">
      <h3>Messages</h3>
      <div class="overflowable">
        <p ng-repeat="message in messages" ng-class="{alert: message.user == 'chatroom'}">: </p>
      </div>
    </div>
    <div class="col">
      <h3>Users</h3>
      <div class="overflowable">
        <p ng-repeat="user in users"></p>
      </div>
    </div>
    <div class="clr">
      <form ng-submit="sendMessage()">
        Message:
        <input size="60" ng-model="message">
        <input type="submit" value="Send"></form>
    </div>
    <div class="clr">
      <h3>Change your name</h3>
      <p>Your current user name is </p>
      <form ng-submit="changeName()">
        <input ng-model="newName">
        <input type="submit" value="Change Name"></form>
    </div>
  </div>
  <script src="lib/angular/angular.js"></script>
  <script src="/socket.io/socket.io.js"></script>
  <script src="js/app.js"></script>
  <script src="js/services.js"></script>
  <script src="js/controllers.js"></script>
  <script src="js/filters.js"></script>
  <script src="js/directives.js"></script>
</body>
</html>

js/app.js:

angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives']);       

js/services.js:

angular.module('myApp.services', [])
.value('version', '0.1')
.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);
                    }
                });
            })
        }
    };
});

js/controllers.js:

/* Controllers */

function AppCtrl($scope, socket) {

  // Socket listeners
  // ================
  socket.on('init', function (data) {
    $scope.name = data.name;
    $scope.users = data.users;
  });

  socket.on('send:message', function (message) {
    $scope.messages.push(message);
  });

  socket.on('change:name', function (data) {
    changeName(data.oldName, data.newName);
  });

  socket.on('user:join', function (data) {
    $scope.messages.push({
      user: 'chatroom',
      text: 'User ' + data.name + ' has joined.'
    });
    $scope.users.push(data.name);
  });

  // add a message to the conversation when a user disconnects or leaves the room
  socket.on('user:left', function (data) {
    $scope.messages.push({
      user: 'chatroom',
      text: 'User ' + data.name + ' has left.'
    });
    var i, user;
    for (i = 0; i < $scope.users.length; i++) {
      user = $scope.users[i];
      if (user === data.name) {
        $scope.users.splice(i, 1);
        break;
      }
    }
  });

  // Private helpers
  // ===============

  var changeName = function (oldName, newName) {
    // rename user in list of users
    var i;
    for (i = 0; i < $scope.users.length; i++) {
      if ($scope.users[i] === oldName) {
        $scope.users[i] = newName;
      }
    }

    $scope.messages.push({
      user: 'chatroom',
      text: 'User ' + oldName + ' is now known as ' + newName + '.'
    });
  }

  // Methods published to the scope
  // ==============================

  $scope.changeName = function () {
    socket.emit('change:name', {
      name: $scope.newName
    }, function (result) {
      if (!result) {
        alert('There was an error changing your name');
      } else {

        changeName($scope.name, $scope.newName);

        $scope.name = $scope.newName;
        $scope.newName = '';
      }
    });
  };

  $scope.messages = [];

  $scope.sendMessage = function () {
    socket.emit('send:message', {
      message: $scope.message
    });

    // add the message to our model locally
    $scope.messages.push({
      user: $scope.name,
      text: $scope.message
    });

    // clear message box
    $scope.message = '';
  };
}

Then I run the angularjs in localhost:8000. In the webpage it seems I can send something which caused the bower to update:

[Mon, 28 Jul 2014 20:10:13 GMT] "GET /app/lib/angular/angular.js" "Mozilla/5.0 (
Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.1
53 Safari/537.36"
[Mon, 28 Jul 2014 20:10:13 GMT] "GET /socket.io/socket.io.js" "Mozilla/5.0 (Wind
ows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 S
afari/537.36"

However the socket.io running on localhost:3000 receives nothing.

I guess I must have something wrong in the connection between angularjs and socket.io, such as the

<script src="/socket.io/socket.io.js"></script> 

in the index.html, or the

var socket = io.connect(); 

in the js/services.js.

I tried to change them to

<script src="http://127.0.0.1:3000/socket.io/socket.io.js"></script>

or

<script src="http://localhost:3000/socket.io/socket.io.js"></script>

or

var socket = io.connect('http://127.0.0.1:3000');

or

var socket = io.connect('http://localhost:3000');

or

var socket = io.connect('http://localhost');

but nothing works. Maybe I am on a completely wrong way.

So I copy paste my code here, hope someone can help me. Any help or suggestions will be grateful.

UPDATE Now it seems the client can connect to the server, but can't load the controller correctly. Not sure how to fix it.

4
  • Is /scripts/socket.js your server side handler? Commented Jul 28, 2014 at 21:23
  • @NathanRomano Yes, it is. Commented Jul 28, 2014 at 21:27
  • Does /script/socket.io.js resolve to a 404? Commented Jul 28, 2014 at 21:29
  • @NathanRomano Well, I just tested it again. If I put the "<script src="127.0.0.1:3000/socket.io/socket.io.js"></script>" in the index.html, I can access the socket.io.js via the link in the Inspect Element. If it is <script src="/socket.io/socket.io.js"></script>, the link "/socket.io/socket.io.js" in Inspect Element displays an empty page. Commented Jul 28, 2014 at 21:38

1 Answer 1

2

Finally figured out what's wrong with the code above after an entire day.

1.The client should connect the socket.io server by adding explicit IP, that is:

in the services.js:

var socket = io.connect("http://127.0.0.1:3000");

in the index.html:

<script src="http://127.0.0.1:3000/socket.io/socket.io.js"></script>  

2.Notice that there are no path and file lib/angular/angular.js in the angular-seed folder. Need to manually create the folder and add the file.

3.The code in the quesion did not display the data correctly.

This is the code I fixed all the bugs and it can work smoothly. https://github.com/shaosh/angular-socketio-chatroom-example

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

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.