带有promise的服务和$ watchCollection不更新值

时间:2013-12-29 01:02:07

标签: javascript angularjs angularjs-directive

我正在尝试使用MongoDB和AngularJS构建实时服务消息。出于某种原因,当我的“messaging”集合中有新数据时,不会触发Messaging.getAllMessages()服务,并且使用$ watchCollection不会在视图中更新我的数据。

这是在我的 services.js 中,重要的功能是 getAllMessages()

angular.module('myApp')
.factory('Messaging', function($resource, $http, $q, $rootScope){
      var myData = {};

      return {
          sendMessage: function(message, success, error) {
              $http.post('/api/v1/users/' + message.to.id + '/messages', message).success(function(res) {
                toastr.success('Message sent');
              }).error(function(error) {
                toastr.error("Error on save");
              });
          },
          getAllMessages: function(userId) {
            var deferred = $q.defer();
            if(!myData) {
               deferred.resolve(myData);
            } else if (userId && userId !== '') {
              $http.get('/api/v1/users/' + userId+ '/messages').success(function(data) {
                  myData = data;
                  deferred.resolve(myData);
                  // update angular's scopes
                  $rootScope.$$phase || $rootScope.$apply();
               });
              } else { 
                 deferred.reject();
              }

              return deferred.promise;
          },
          markAsRead: function(ids, success, error) {
            var deferred = $q.defer();
            if(!myData) {
               deferred.resolve(myData);
            } else if (ids && ids !== '') {
              $http.put('/api/v1/users/' + ids.userId + '/messages/' + ids.messageId).success(function(data) {
                  myData = data;
                  deferred.resolve(myData);
                  // update angular's scopes
                  $rootScope.$$phase || $rootScope.$apply();
               });
              } else { 
                 deferred.reject();
              }

              return deferred.promise;
          },
          getMessage: function(ids, success, error) {
            return $http.get('/api/v1/users/' + ids.userId + '/messages/' + ids.messageId);
          },
          deleteMessage: function(ids, success, error) {
            return $http.delete('/api/v1/users/' + ids.userId + '/messages/' + ids.messageId);
          }
    }
});

这是在 directive.js

angular.module('myApp').directive('messaging', ['$log', 'Messaging', function($log, Messaging){
  return {
    scope: true,
    restrict: 'A', // E = Element, A = Attribute, C = Class, M = Comment
    templateUrl: '/views/templates/messaging-dropdown.html',
    replace: true,
    link: function($scope, iElm, iAttrs, controller) {

      Messaging.getAllMessages($scope.user.id).then(function(myData) {

          $scope.allMessages = myData;
          $scope.newMessages = 0;

          $scope.$watchCollection('allMessages', function(newVal, oldVal){
            if(newVal !== oldVal) {

                $scope.newMessages = 0;

                // Count the number of unread messages

                for (var i = myData.length - 1; i >= 0; i--) {
                   if(myData[i].read === false) {
                      $scope.newMessages++;
                   }
                };
            }
        }, true);
       }, function() {
           // request failed (same as 'return false')
           $scope.allMessages = 'i got the error';
       });
    }
  };
}]);

这是模板, messaging-dropdown.html

<div>
<a ng-click="showMessages()" ng-class="{clicked: messagesToggled}">
    <i class="fa fa-envelope"></i>
    <span class="badge" ng-show="newMessages > 0">{{newMessages}}</span>
  </a>
  <ul class="dropdown-menu" ng-show="messagesToggled">

    <li ng-repeat="message in allMessages | limitTo: 5 | orderBy:'sent'">
      <a ng-href="/users/{{message.to.id}}/messages/{{message._id}}" ng-class="{unread: !message.read}">
        <img ng-src="{{message.from.image}}" alt="" class="img-circle">
        <span class="body">
          <span class="from">{{message.from.name}}</span>
          <span class="message">
            {{message.text}}
          </span> 
          <span class="time">
            <span>{{message.sent}}</span>
          </span>
        </span>
      </a>
    </li>
    <li class="footer">
      <a ng-href="/users/{{user.id}}/messages">See all <b>{{allMessages.length}}</b> messages</a>
    </li>
</div>

如您所见,当watchve返回的数组中有新数据时,监视器未更新$ scope.newMessages。我缺少一些东西,是否需要socket.io或Pusher / Pubnub来实现所需的行为?提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

感谢@Sunil指出这一点。我原本以为,$ watch()和$ watchCollection()会根据$ digest()循环提供的特定时间间隔自动拉取并检查服务中的新数据。

我发布了我的解决方案需要某种触发器,以便在可用时从服务中提取新数据。因此,我使用socket.io实现了私有消息传递通道,以触发对方发送的消息更新。

这是更新的指令:

更新了 directive.js

angular.module('myApp').directive('messaging', ['$log', 'Messaging', 'messagingSocket', function($log, Messaging, messagingSocket){
  // Runs during compile
  return {
    scope: true,
    restrict: 'A', // E = Element, A = Attribute, C = Class, M = Comment
    templateUrl: '/views/templates/messaging-dropdown.html',
    replace: true,
    link: function($scope, iElm, iAttrs, controller) {

      messagingSocket.emit('setUser', {id: $scope.user.id});

      $scope.allMessages = function(){

        Messaging.getAllMessages($scope.user.id).then(function(myData) {

          $scope.allMessages.messages = myData;

       }, function() {
           // request failed (same as your 'return false')
           $scope.allMessages = 'i got the error';
       });
      };

      $scope.allMessages();

      messagingSocket.forward('new message', $scope);

      $scope.$on('socket:new message', function (event, data) {

        $scope.allMessages();

      });

      $scope.$watchCollection('allMessages.messages', function(newVal, oldVal){
        if(newVal !== oldVal) {

            $scope.newMessages = 0;

            // Count the number of unread messages

            for (var i = $scope.allMessages.messages.length - 1; i >= 0; i--) {
               if($scope.allMessages.messages[i].read === false) {
                  $scope.newMessages++;
               }
            };
        }
    }, true);

    }
  };
}]);