AngularJS不使用socket.io刷新视图

AngularJS不使用socket.io刷新视图,angularjs,node.js,socket.io,Angularjs,Node.js,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

我有一个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}}

问题在于,这种变化并非真正的“实时”。我的意思是,
connected
值可能在范围内更改,但需要在页面上执行操作(按钮clic),以使视图更新为正确的值。如果我没有在页面上执行任何操作,则不会刷新该值


我可能忘了什么。。但是我不知道是什么..

因为套接字事件在AngularJS之外,所以您需要理解范围:

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

您可以通过阅读来真正理解为什么需要这样做

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()
将执行作为参数传递的函数,然后调用$scope.$digest()来更新任何绑定或观察程序。

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';
      });
    });
}]);
现在这可能相当麻烦,所以您可以创建一个工厂来为您处理

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

编辑

如前所述,由于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);
          }
        });
      })
    }
  };
});

不要在代码中放入
$scope.$digest()
,如果应用程序增长并且$digest将更频繁地被触发,它将在progres中抛出JS错误
$digest
使用
$scope.$apply
或在angularjs的更新版本中
$scope.$applyAsync
这就是为什么Angular1.3用户在不指定时间的情况下使用
$timeout
对其进行微调,从angular 1.3开始,有一个专门为此设计的
ApplySync
。我不知道applyAsync。从angular 1.3开始使用
$scope.$applyAsync
哪一个更好呢?我的错,错过了。好东西:)坦白地说,这是最好的解决方案,将socket.io包装为angular service使其变得很好easier@maurycy为作者添加了更多可见的学分,并添加了一个建议使用
$applyAsync