在SSE回调之后AngularJS和处理范围刷新

时间:2015-08-23 15:27:17

标签: javascript angularjs

我对Angular和JS都比较陌生,但请耐心等待。我见过很多类似的问题,但这些问题似乎都没有回答我的问题。

我有以下服务,订阅包含Twitter消息的消息流

angular.module('twitterstream.services', [])
    .factory('tweetService', function() {
        var tweets = [];
        var tweetFeed = new EventSource("/feed");
        tweetFeed.addEventListener("message", feedCallback, false);

        return {
            getTweets: getTweets
        };

        function getTweets() {
            return tweets;
        }       

        function feedCallback(message) {
            var tweet = JSON.parse(message.data);
            tweets.push(tweet);
        }
    })

在我的控制器中,我正在观看服务的tweets属性:

angular.module('twitterstream.controllers', ['twitterstream.services'])
    .controller('tweetController', ['$scope', 'tweetService', function($scope, tweetService) {
        $scope.tweets = [];

        $scope.$watch(
            function() {
                return tweetService.getTweets();
            },
            function(newVal, oldVal) {
                $scope.tweets = newVal;
            }
        );
    }]);

这是我的index.html

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>

    <script src="bower_components/angular/angular.js"></script>
    <script src="scripts/app.js"></script>
    <script src="scripts/controllers/controllers.js"></script>
    <script src="scripts/services/services.js"></script>
  </head>
  <body data-ng-app="twitterstream">
    Hello jerks
    <br>
    <div data-ng-controller="tweetController">
      <ul>
        <li data-ng-repeat="tweet in tweets">
          {{tweet.text}}
        </li>
      </ul>    
    </div>
  </body>
</html>

现在,问题在于:<ul>未获得更新。

要明确:

  • 服务器已发送事件有效,我已检查此
  • EventStream回调也可以,服务中的tweets正在更新
  • $ watch功能也可以,控制器中的tweets也会更新

但是UI没有得到更新。但是,如果我打电话

angular.element($("div")).inheritedData().$scope.$apply();

从开发人员控制台,整个DOM按预期很好地刷新。

这促使我在控制器中手动插入$ apply调用:

$scope.$watch(
    function() {
        return tweetService.getTweets();
    },
    function(newVal, oldVal) {
        $scope.tweets = newVal;
        $scope.$apply();          // <---- Right over here
    }
);

但是,只要应用程序启动,就会产生以下错误:

[$rootScope:inprog] $digest already in progress

我在SO上找到的大多数示例都没有将对EventSource的订阅分成服务,只是将所有内容都保存在一个控制器中。当然,我的服务中没有$ scope对象,所以我不能在EventSource回调中调用$ apply。

最优雅的解决方案是什么?

1 个答案:

答案 0 :(得分:2)

我会轻易做到:

angular.module('twitterstream', []);

angular.module('twitterstream.services', [])
.factory('tweetService', function() {
   var tweets = [];
   var tweetFeed = new EventSource("/feed");

   // the factory returns a function waiting for a callback that will handle the controller
   return {
       getTweets: function(callback) {
         tweetFeed.addEventListener("message", callback, false);
       }
   }; 
});

angular.module('twitterstream.controllers', ['twitterstream.services'])
.controller('tweetController', ['$scope', 'tweetService', function($scope, tweetService) {
      // the controller will assign the value when 'message' event is ready
      $scope.tweets = tweetService.getTweets(function(response) {
          var tweets = JSON.parse(response.data);
          $scope.tweets = tweets;
      });
}]);

我希望这可以帮助你:)