LazioTibijczyk
LazioTibijczyk

Reputation: 1937

Pushing into array doesn't update the view

I have created this fake conversation that loads last 20 messages and the next 20 or remaining messages when scrolled to the top of the page. For some reason the remaining messages are added successfully to vm.messages array (I can see that in the console) but do not become visible on the screen anytime after loadMoreMessages is called later.

I have absolutely no idea why this is happening... I thought this might be because the view does not update correctly however when I created a function vm.reply, it has no problem adding one more message dynamically.

I have managed to load messaged 30 to 10 as expected but the first 10 do not appear on the screen after scrolling up.

angular.module('app',['ui.bootstrap'])

.controller('mainCtrl', function($location, $anchorScroll, $document, $window) {
  var vm = this;
  vm.messagesInPart = 20; //number of messages in one part
  vm.messagesLoaded = 0;
  vm.conversation = [];
  vm.messages = [];
  
  $document.on('scroll', function() {
    if($window.scrollY === 0) {
       console.log('top of the page');
       loadMoreMessages();
    }
  });
  
  //fake conversation
  function getConversation() {
    for(var i = 1; i < 30; i++) {
      vm.conversation.push({
        side: 'left',
        badgeClass: 'info',
        badgeIconClass: 'glyphicon-comment',
        content: "My own message " + i,
        userName: ''
      });
    }
    
    scrollToTheReply();
  }
  
  getConversation();
  
  function loadMoreMessages() {
     vm.messagesLeftToLoad = vm.conversation.length - vm.messagesLoaded;

     if(vm.messagesLeftToLoad > 0) {
        var iterationsUpTo = vm.messagesLeftToLoad >= vm.messagesInPart ? vm.messagesLeftToLoad - vm.messagesInPart : 0;
       
        console.log('iterationsUpTo = ', iterationsUpTo);

        for(var i = vm.messagesLeftToLoad - 1; i >= iterationsUpTo; i--) {
          vm.messages.unshift({
             side: vm.conversation[i].side,
             badgeClass: vm.conversation[i].badgeClass,
             badgeIconClass: vm.conversation[i].badgeIconClass,
             userName: vm.conversation[i].userName,
             content: vm.conversation[i].content
          });

          vm.messagesLoaded++;
       }
       
       console.log('vm.messages = ', vm.messages);
     }
  }
  
  loadMoreMessages();
  
  function scrollToTheReply() {
	$location.hash('reply');
	$anchorScroll();
  }

  vm.reply = function() {
     vm.messages.push({
       side: 'left',
       badgeClass: 'info',
       badgeIconClass: 'glyphicon-comment',
       userName: '',
       content: 'Reply msg'
     });
  }
})
<html ng-app="app">
 <head>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/rpocklin/angular-timeline/dist/angular-timeline-bootstrap.css"/>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/rpocklin/angular-timeline/dist/angular-timeline.css"/>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.5/angular.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/rpocklin/angular-timeline/dist/angular-timeline.js"></script>
 </head>
 <body>
    <div ng-controller="mainCtrl as vm">
       <div style="float: left;">
          <timeline>
             <timeline-event ng-repeat="message in vm.messages" side="{{message.side}}">
                <timeline-badge class="{{message.badgeClass}}">
                   <i class="glyphicon {{message.badgeIconClass}}"></i>
                </timeline-badge>
                <timeline-panel class="{{message.badgeClass}}">
                   <timeline-heading>
                      <h4>{{message.userName}}</h4>
                   </timeline-heading>
                   <p>{{message.content}}</p>
                </timeline-panel>
              </timeline-event>
            </timeline>
         </div>
      <div style="margin-top:20px;">
        <button type="button" id="reply" ng-click="vm.reply()">Reply</button>
      </div>
    </div>
  </body>
 </html>

Upvotes: 2

Views: 53

Answers (1)

Srdjan
Srdjan

Reputation: 582

You're not in a digest loop.

Trigger it with $scope.$apply();, $scope.digest(); or $timeout(); functions when calling loadMoreMessages(); function.

Example:

$document.on('scroll', function() {
  if($window.scrollY === 0) {
     $timeout(function() {
      loadMoreMessages();
     });
  }
});

And don't forget to inject $timeout into your controller if you are going to use it.

Upvotes: 1

Related Questions