AngularJS不会使用socket.io刷新视图

我有一个node.js服务器应用程序与以下设置:

var express = require('express'); var io = require('socket.io'); var http = require('http'); var app = express(); app.use(express.static('public')); var server = http.createServer(app); io = io.listen(server); io.on('connection', function(socket){ console.log('a user is connected'); }); device.on('disconnect', function() { console.log('we got disconnected! :( '); io.emit('deviceDisconnection'); }); 

这里的设备是蓝牙连接的设备。 而且,在客户端,我有一个AngularJS应用程序,在应用程序的控制器中声明以下事件订阅:

 var appFront = angular.module(appFront , []) .controller('mainController', ['$scope', '$http', function($scope,$http) { var socket = io(); socket.on('deviceDisconnection', function(){ $scope.connected = 'TRUE'; }); }]); 

当然,在视图中,我有以下约束:

 <div class="row"> <p>{{connected}}</p> </div> 

问题在于变化并不是真正的“实时”。 我的意思是, connected值可能在范围中改变,但是需要在页面上执行一个操作(buttonclic),使视图以正确的值更新。 如果我没有在页面上做任何事情,价值不刷新。

我可能忘了一些东西..但我不知道是什么..

Socket.io事件是AngularJS的外部,所以你需要警告AngularJS发生了一个变化:

 var appFront = angular.module(appFront , []) .controller('mainController', ['$scope', '$http', function($scope,$http) { var socket = io(); socket.on('deviceDisconnection', function(){ $scope.$applyAsync(function () { $scope.connected = 'TRUE'; }); }); }]); 

现在这可能非常麻烦,所以你可以创build一个工厂来为你处理

 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); } }); }) } }; }); 

你可以在这里查看关于这个代码片段的更多信息,学分转到作者Brian Ford。

编辑

正如maurycy所说的那样,由于Angular 1.3最好使用$ applyAsync,并且由于上面的代码片段是在2012年编写的,所以有些过时,所以更好的版本会是这样的

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

Angular没有意识到其上下文以外的变化。 要解决这个问题,你应该使用$apply像这样:

  var appFront = angular.module(appFront , []).controller('mainController', ['$scope', '$http', function($scope,$http) { var socket = io(); socket.on('deviceDisconnection', function(){ $scope.$apply(function () { $scope.connected = 'TRUE'; }); }); }]); 

$scope.$apply()将执行一个作为parameter passing的函数,然后调用$ scope。$ digest()来更新绑定或监视器。

由于套接字事件在AngularJS之外,因此需要消化范围:

 socket.on('deviceDisconnection', function(){ $scope.connected = 'TRUE'; $scope.$digest(); }); 

你可以阅读这个有趣的文章 ,真正理解为什么这是必要的