AngularJS + Socket.IO - 如何更新模型?

Posted

技术标签:

【中文标题】AngularJS + Socket.IO - 如何更新模型?【英文标题】:AngularJS + Socket.IO - how to update model? 【发布时间】:2013-09-01 11:29:11 【问题描述】:

所以我有了这个用 AngularJS 制作的基本 CRUD Todo 应用程序。然后我想我想用一些 Socket.IO 来增加它的趣味性,使它成为一个实时网络应用程序。但是,我在让它正常工作时遇到了一些问题。

设置: 约曼(鲍尔+咕噜) AngularJS 要求JS NodeJS + MongoDB Socket.IO

我的“咕噜服务器”在 localhost:9000 上运行,而我的 NodeJS/MongoDB/Socket.IO 服务器在 localhost:4711 上运行

目前使用 Socket.IO 的功能是创建和删除待办事项,但我似乎不知道如何更新我的待办事项。我认为这很容易。

这是代码。

Socket.js:

var io = require('socket.io');

exports.initialize = function(server) 
  io = io.listen(server);
  io.sockets.on('connection', function(socket) 
    socket.on('message', function(message) 
      message = JSON.parse(message);
      socket.get('deletedTodo', function(err, nickname) 
        socket.broadcast.send(JSON.stringify(message));
        socket.send(JSON.stringify(message));
      );
    );
    socket.on('delete_todo', function(data) 
      socket.set('deletedTodo', data.title, function() 
        socket.emit('todo_delete', data);

        socket.broadcast.emit('todoDeleted', data);
      );
    );
    socket.on('update_todo', function(data) 
      socket.broadcast.emit('todoUpdated', data);
    )
  );

这是我的客户端代码。

Services.js:

/*global define*/
define(['angular'], function(angular) 
 'use strict';

 return angular.module('services', [])
   .factory('Todo', function($resource) 
     //var baseUrl = 'http://designit-todo.eu01.aws.af.cm/api/todos/:id';
     var baseUrl = 'http://localhost:port/api/todos/:id';
     return $resource(baseUrl,
       port: ':4711', id: '@_id', 
       'update': method:'PUT',
       'delete': method:'DELETE', isArray: true
     );
   )
   .factory('socket', function($rootScope) 
     var socket = io.connect('http://localhost:4711');
     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);
             
           );
         );
       ,
       send: function(eventName, data, callback) 
         socket.send(eventName, data, function() 
           var args = arguments;
           $rootScope.$apply(function() 
             if (callback) 
               callback.apply(socket, args);
             
           );
         );
       
     
   );
);

Controllers.js:

/*global define*/
define(['angular', 'services/services'], function(angular) 
'use strict';

return angular.module('controllers', ['services'])
.controller('Todos', ['$scope', '$resource', 'Todo', '$location', 'socket',        function($scope, $resource, Todo, $location, socket) 
  // Grab all todos.
  $scope.todos = Todo.query();

  socket.on('message', function(data) 
    // Grab all todos when new added via socket.
    $scope.todos = Todo.query();

    $scope.todos.push(data);
  );

  // Complete/update todo.
  $scope.todoCompleted = function(todo) 
    todo.$update();
    socket.emit('update_todo', todo);
  
  socket.on('todoUpdated', function(todo) 
    // Update on all connected clients.
    console.log(todo);
  );

  $scope.removeTodo = function(todo) 
    var index = $scope.todos.indexOf(todo);
    socket.emit("delete_todo", JSON.stringify(index));
    $scope.todos.splice(index, 1);
    todo.$remove();
  
  socket.on('todoDeleted', function(index) 
    $scope.todos.splice(index, 1);
  );
])
.controller('Single', ['$scope', '$resource', '$routeParams', 'Todo', '$timeout', '$location', function($scope, $resource, $routeParams, Todo, $timeout, $location) 
  // Grab just a single todo
  $scope.todo = Todo.get( id: $routeParams.id );
  // Throttle the update PUT request
  var saveTimeout;
  $scope.save = function() 
    $timeout.cancel(saveTimeout);
    saveTimeout = $timeout(function() 
      // Save the todo and then update the scope
      $scope.todo.$update(function(updated_todo) 
        $scope.todo = updated_todo;
      );
    , 1000);
  ;
])
.controller('Add', ['$scope', '$resource', 'Todo', '$location', 'socket', function($scope, $resource, Todo, $location, socket) 
  $scope.todo = new Todo();

  $scope.save = function() 
    if ($scope.todo.title) 
      $scope.todo.$save(function(data) 
        console.log(data);
        socket.send(JSON.stringify(data));
        $location.path('/');
      );
    
  
]);
);

所以我的问题在于这段代码:

// Complete/update todo.
$scope.todoCompleted = function(todo) 
  todo.$update();
  socket.emit('update_todo', todo);

socket.on('todoUpdated', function(todo) 
  // Update on all connected clients.
  console.log(todo);
);

当我使用 console.log(todo) 时,我得到了 todo,但我可以对其执行“todo.$update”。我也尝试过类似的方法:

  socket.on('todoUpdated', function(todo) 
    var thisTodo = Todo.get(id: todo._id);
    console.log(thisTodo);
  );

但是一旦我尝试这样做Todo.$update() 我得到一个错误:

PUT http://localhost:4711/api/todos 404 (Not Found) :4711/api/todos:1

我做错了什么?如果我在代码中做错了什么,请纠正我。我对 AngularJS 和 Socket.IO 还是很陌生。

【问题讨论】:

问题不在于socket.io,这一切似乎都有效。问题在于您的 API。显然,您正在尝试使用 id 1 更新待办事项,但服务器似乎找不到此待办事项。 Postman 是一个测试 API 的好工具:chrome.google.com/webstore/detail/postman-rest-client/… 嗯.. 我不认为我的 API 有问题?我已经尝试使用适用于 Chrome 的 Advanced Rest Client,GET、POST、PUT 和 DELETE 都可以在 localhost:4711/api/todos 上正常工作 检查 Angular 试图在你的开发工具中执行的确切 PUT 请求,并将其与您使用 Rest Client 执行的请求进行比较。那么 PUT 请求一定有问题。 我刚刚在 .todoCompleted 方法上尝试了这个:var thisTodo = Todo.get(id: todo._id); thisTodo.$update(); 现在这两个客户端都出现了同样的错误。 您可以在此处查看错误:cl.ly/image/3u1b0a2m0G1c 和此处:cl.ly/image/432R3n2s062A 【参考方案1】:

我找到了另一个解决方案,但不确定它是否是正确的方法:

socket.on('todoUpdated', function(updated_todo) 
  for (var i in $scope.todos) 
    if ($scope.todos[i]._id == updated_todo._id) 
      $scope.todos[i] = updated_todo;
    
  
);

所以在 Todos 控制器中,我有 $scope.todos 来保存所有的 todos。然后我遍历所有这些,在 id 上找到匹配项并将找到的 todo 设置为新更新的 todo。

如果有更好的方法,请告诉我:)

【讨论】:

以上是关于AngularJS + Socket.IO - 如何更新模型?的主要内容,如果未能解决你的问题,请参考以下文章

改进这个 AngularJS 工厂以与 socket.io 一起使用

如何使用 Express、AngularJS、Socket.io 广播和获取通知?

Angularjs socket.io 服务

AngularJS 不使用 socket.io 刷新视图

AngularJS:通过 https 使用 socket.io 的聊天应用程序

使用 angularjs 和 socket.io 实时保存和显示评论