2013-12-09 47 views
3

我在Angular WebApp中使用socket.io客户端。我把它包装在一个服务中,但这可能不一定有兴趣。但是,由于输入的数据与使用该服务的控制器的范围不同,我总是需要拨打$scope.$apply。更糟糕的是,我发现了一些情况(在连接/重新连接期间),我必须使用safeApply,如here所述。

据我所知,这是一个Angular Anti-Pattern,但我没有看到解决方法。

是否有一个通用的方法来解决这个问题(最好是在服务中),不会污染控制器的很多$scope.$apply/safeApply

BR, 丹尼尔

这里也是一些代码,工作,但不是很好:

angular.module('mean') 
    .controller('ConnectionStateController', function ($scope) { 
     $scope.safeApply = function (fn) { 
      var phase = this.$root.$$phase; 
      if (phase == '$apply' || phase == '$digest') { 
       if (fn && (typeof (fn) === 'function')) { 
        fn(); 
       } 
      } else { 
       this.$apply(fn); 
      } 
     }; 

     var socket = io.connect('http://localhost:3000'); 
     $scope.message = 'Not connected'; 
     socket.on('connect', function() { 
      $scope.safeApply(function() { 
       $scope.message = "Connected"; 
      }); 
     }); 
    }); 

回答

0

在你的情况,你知道socket.io操作总是要异步运行,这使得它成为valid place to use $scope.$apply (towards the bottom of the page)

我会推荐不使用safeApply并明确呼吁$scope.$apply。使用safeApply将掩盖实施过程中的真正错误。此外,如果您要将代码封装到服务中,则可以在服务中注入$rootScope,并调用$rootScope.$apply中的异步函数。那么你不需要在每个控制器中调用$scope.$apply

+0

哦,伙计。我仍然是一个小菜鸟。毕竟,我实际上并不知道如何在服务中使用'$ scope。$ apply'。把它放到'$ rootScope'似乎也不是一个很好的选择(我知道你们经常这样做),因为这可以被内部作用域的属性覆盖,对吧? – Daniel

0

我会自己回答这个问题,因为我有一个使用defer s的工作解决方案。不过,我不确定我是否做得对。这里的服务:

angular.module('mean') 
    .factory('ConnectionService', function ($q, $timeout) { 
     var bindings = {}; 
     var socket = io.connect('http://localhost:3000'); 
     // catch all events by overriding the socket's $emit 
     var $emit = socket.$emit; 
     socket.$emit = function (event, obj) { 
      console.log('***', 'on', '"' + event + '"', obj); 
      if (bindings.hasOwnProperty(event)) { 
       bindings[event].notify(obj); 
      } 
      $emit.apply(socket, arguments); 
     }; 

     return { 
      socket: socket, 
      observe: function (event, callback) { 
       if (!bindings.hasOwnProperty(event)) { 
        bindings[event] = $q.defer(); 
       } 
       bindings[event].promise.then(null, null, function (data) { 
        callback.apply(this, [ data ]); 
       }); 
      } 
     }; 
    }); 

这允许控制器使用这样的服务:

ConnectionService.observe('news', function (data) { 
    $scope.message = data; 
}); 

不知道,如果这是一个很好的解决方案,或者如果它有副作用,我不看然而。

BR, Daniel