2013-12-09 83 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