Angularjs : Scroll to bottom of div

20,658

Move the scroll-to-bottom directive to the md-content element

 <!-- MOVE directive here -->
 <md-content ͟s͟c͟r͟o͟l͟l͟-͟t͟o͟-͟b͟o͟t͟t͟o͟m͟=͟"͟c͟t͟r͟l͟.͟m͟e͟s͟s͟a͟g͟e͟s͟"͟ layout="column"
             style="background-color: #F5F5F5;" 
             ng-style="{'height':ctrl.messageWindowHeight}">
      <div class="chat-box">
        <!-- NOT HERE -->
        <ol class="discussion" ̶s̶c̶r̶o̶l̶l̶-̶t̶o̶-̶b̶o̶t̶t̶o̶m̶=̶"̶c̶t̶r̶l̶.̶m̶e̶s̶s̶a̶g̶e̶s̶"̶ >
          <li ng-repeat="message in ctrl.messages track by $index" id="msg-{{$index}}">
            {{message}}
          </li>
        </ol>
      </div>
  </md-content>

The scroll-to-bottom directive needs to operate on the element that is actually scrolling. The element that is scrolling is the <md-content> element because its height is restricted by the CSS created by its ng-style directive. The <ol> element is not scrolling and its scrollHeight property is constant.

The DEMO

var app=angular.module('myApp', ['ngMaterial'] );
app.controller('ChatCtrl', function($window, $anchorScroll){
  var self = this;
  self.messageWindowHeight = parseInt($window.innerHeight - 170) + 'px';
  self.messages = [];
  for(var i = 1 ; i<=200;i ++){
    self.messages.push(i);
  }
  
  self.user = { text : ""};
  self.send = function(){
    self.messages.push(angular.copy(self.user.text));
    self.user.text = "";
  }
});

app.directive('scrollToBottom', function($timeout, $window) {
    return {
        scope: {
            scrollToBottom: "="
        },
        restrict: 'A',
        link: function(scope, element, attr) {
            scope.$watchCollection('scrollToBottom', function(newVal) {
                if (newVal) {
                    $timeout(function() {
                        element[0].scrollTop =  element[0].scrollHeight;
                    }, 0);
                }

            });
        }
    };
});
/* Styles go here */
.chat-box {
    padding: 8px;
    border-radius: 8px;
}
.message-box {
    border-top: 1px solid #E0E0E0;
    position: fixed;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 120px;
    background: white;
}

.message {
    overflow: scroll;
    margin: 4px;
    border: 1px solid #E0E0E0;
    -webkit-border-radius: 8px;
    -moz-border-radius: 8px;
    border-radius: 8px;
    height: 110px;
}
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.9/angular-material.css">
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:300,400,500,700,400italic">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-animate.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-aria.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.9/angular-material.js"></script>
<body ng-app='myApp' layout="column" layout-fill ng-controller="ChatCtrl as ctrl">
  <!-- content starts here -->
  <md-toolbar class="md-whiteframe-z2">
    <div class="md-toolbar-tools">
      <h2>
          hello
        </h2>
    </div>
  </md-toolbar>
  <md-content scroll-to-bottom="ctrl.messages" layout="column" style="background-color: #F5F5F5;" ng-style="{'height':ctrl.messageWindowHeight}">
      <div class="chat-box">
        <ol class="discussion">
          <li ng-repeat="message in ctrl.messages track by $index" id="msg-{{$index}}">
            {{message}}
          </li>
        </ol>
      </div>
  </md-content>
  <form name="userForm" novalidate ng-submit="ctrl.send()" layout="row" layout-padding layout-align="center center" class="message-box">
    <div class="message" flex>
      <md-input-container class="md-block">
        <input type="text" name="text" ng-model="ctrl.user.text" />
      </md-input-container>
    </div>
    <md-button class="md-icon-button" type="submit">
      send
    </md-button>
  </form>
</body>
Share:
20,658
nitin
Author by

nitin

All things javascript.

Updated on September 26, 2020

Comments

  • nitin
    nitin over 3 years

    I'm having trouble scrolling to last message.

    var app=angular.module('myApp', ['ngMaterial'] );
    app.controller('ChatCtrl', function($window, $anchorScroll){
      var self = this;
      self.messageWindowHeight = parseInt($window.innerHeight - 170) + 'px';
      self.messages = [];
      for(var i = 1 ; i<=200;i ++){
        self.messages.push(i);
      }
      
      self.user = { text : ""};
      self.send = function(){
        self.messages.push(angular.copy(self.user.text));
        self.user.text = "";
      }
    });
    
    app.directive('scrollToBottom', function($timeout, $window) {
        return {
            scope: {
                scrollToBottom: "="
            },
            restrict: 'A',
            link: function(scope, element, attr) {
                scope.$watchCollection('scrollToBottom', function(newVal) {
                    if (newVal) {
                        $timeout(function() {
                            element[0].scrollTop =  element[0].scrollHeight;
                        }, 0);
                    }
    
                });
            }
        };
    });
    /* Styles go here */
    .chat-box {
        padding: 8px;
        border-radius: 8px;
    }
    .message-box {
        border-top: 1px solid #E0E0E0;
        position: fixed;
        right: 0;
        bottom: 0;
        width: 100%;
        height: 120px;
        background: white;
    }
    
    .message {
        overflow: scroll;
        margin: 4px;
        border: 1px solid #E0E0E0;
        -webkit-border-radius: 8px;
        -moz-border-radius: 8px;
        border-radius: 8px;
        height: 110px;
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <link rel="stylesheet" href="style.css">
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.9/angular-material.css">
      <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:300,400,500,700,400italic">
    </head>
    
    <body ng-app='myApp' layout="column" layout-fill ng-controller="ChatCtrl as ctrl">
      <!-- content starts here -->
      <md-toolbar class="md-whiteframe-z2">
        <div class="md-toolbar-tools">
          <h2>
              hello
            </h2>
        </div>
      </md-toolbar>
      <md-content layout="column" style="background-color: #F5F5F5;"
                  ng-style="{'height':ctrl.messageWindowHeight}">
          <div class="chat-box">
            <ol class="discussion" scroll-to-bottom="ctrl.messages">
              <li ng-repeat="message in ctrl.messages track by $index" id="msg-{{$index}}">
                {{message}}
              </li>
            </ol>
          </div>
      </md-content>
      <form name="userForm" novalidate ng-submit="ctrl.send()" layout="row" layout-padding layout-align="center center" class="message-box">
        <div class="message" flex>
          <md-input-container class="md-block">
            <input type="text" name="text" ng-model="ctrl.user.text" />
          </md-input-container>
        </div>
        <md-button class="md-icon-button" type="submit">
          send
        </md-button>
      </form>
    
      <!-- content ends here -->
    
    
      <!-- Angular Material Dependencies -->
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-animate.min.js"></script>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-aria.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.9/angular-material.js"></script>
    
      <script src="script.js"></script>
    </body>
    
    </html>

    Here's a plunk of my code.