user1007665 user1007665 - 6 months ago 9
Node.js Question

socket.io with Angular doesn't display message instantly

I am trying to create instanse message app (chat) using socket.io and Angular.
I have 2 files: index.html, and index.js showed below.
the chat works fine expect that when I press on the "Send" button I don't see the message stright away in the chat window.
I only see the message once I press the input text field with the mouse cursor...
What Am I doing wrong?

i addition, I also see the tag < li > as part of the text. I want this tag to be an html tag, not a text string...

Thanks

index.html

<html>
<head>
<title>My Chat</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
{{ message }}
<form >
<input autocomplete="off" ng-model="exampleText" type="text" />
<button type='button' ng-click="submit()">
Send
</button>
</form>
</div>
<script>

var app=angular.module("myApp", []);
var socket = io();
app.controller("myCtrl", function($scope) {
$scope.message='';
$scope.submit=function(){
socket.emit('chat message', angular.copy($scope.exampleText));
$scope.exampleText='';
return false;
}
socket.on('chat message', function(msg){
$scope.message=$scope.message+" <li> "+ msg;
});
});

</script>
</body>
</html>


index.js

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.use(express.static(__dirname + '/'));
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket){
console.log('a user connected');


socket.on('chat message', function(msg){
io.emit('chat message', msg);
});


socket.on('disconnect', function(){
console.log('user disconnected');
});


});

http.listen(3000, function(){
console.log('listening on *:3000');
});

Answer

First, the message delay. Look at the chat message handler:

socket.on('chat message', function(msg){
  $scope.message=$scope.message+" <li> "+ msg;
});

- the problem here is that message update happens outside of the scope digest loop. Try the following:

socket.on('chat message', function(msg){
  $scope.$apply(function() {
     $scope.message=$scope.message+" <li> "+ msg + "</li>";
  });
});

Next, if you want to get rid of "li" tags showing, you need to stop constructing HTML in your controller and display incoming messages directly. This can be achieved by making "message" an array of messages. In your HTML layout, replace:

{{ message }}

with

<ul>
    <li ng-repeat="message in messages">{{message}}</li>
</ul>

then replace, in the controller

$scope.message='';

with

$scope.messages = [];

and finally change the chat message handler to:

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

This will do the trick.