Service with promise and $watchCollection not updating the values

ぃ、小莉子 提交于 2019-12-23 04:01:49

问题


I'm trying to build real time service messaging with MongoDB and AngularJS. For some reason, when there is new data in my 'messaging' collection, the Messaging.getAllMessages() service is not triggered and my data is not updated in the view, using $watchCollection.

This is in my services.js, the important function is 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);
          }
    }
});

This is in 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';
       });
    }
  };
}]);

And this is the template, 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>

As you see the $scope.newMessages is not updated by the watch, when there is new data in the array returned by the serive. I'm missing something, is there need for socket.io or Pusher/Pubnub to achieve the desired behaviour? Thanks in advance for any help.


回答1:


Thanks @Sunil for pointing that out. I originally thought, that $watch() and $watchCollection(), will pull automatically and check the service for new data based on specific interval provided by the $digest() cycle.

I released that my solution needs some kind of trigger, so that the new data to be pulled from the service when available. So I implemented private messaging channels using socket.io for triggering updates on message sent from the other party.

Here is the updated directive:

Updated 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);

    }
  };
}]);


来源:https://stackoverflow.com/questions/20821083/service-with-promise-and-watchcollection-not-updating-the-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!