AngularJS: How to automatically scroll to the bottom of a div

I cannot seem to scroll to the last message in my chat window.

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.

Answer №1

Relocate 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 should be applied to the scrolling element, which is the <md-content> element due to its height being constrained by the CSS generated by the ng-style directive. The <ol> element does not scroll, as indicated by its constant scrollHeight property.

Check out 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>

Answer №3

Here is an example of angular code that can be used for scrolling down:

<div id="scrollBtn"></div>

const target = document.getElementById("scrollBtn");
target.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" });

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

AngularJS faces an issue where it cannot recognize the selected option if the options set is modified using jQuery

Within an AngularJS (v1.4.14) app containing legacy code, there is a web form that includes the following select tag: <select id="selectCourses" class="input-select" data-ng-model="fields.course" data-courses="form.cou ...

Issues arise with the functionality of CSS and JavaScript after successfully deploying a Next.js and React project to the server side

I need to deploy my React+Next and Node.js projects on the same port. To achieve this, I converted my TypeScript files to JavaScript and moved the .next folder to the backend side. Now, my API and frontend code are functioning on the same port thanks to Ex ...

The function screen.getByText is not available in this context

My experience with jest and react-testing-library has been smooth for the most part, but I encountered some challenges when transitioning to the screen > getByText/etc testing method. Test describe('test the dashboard when loaded', () => { ...

Element Style Does Not Align with Computed Z-Index

Currently, I am in the process of developing an HTML5 video player. However, I have encountered a problem where my custom controls become unclickable once the video element is set to fullscreen mode. This issue arises because the video's z-index is se ...

Unable to retrieve Java variable in JavaScript

Seeking guidance on how to retrieve Json data stored in a Java variable using JavaScript. Instead of accessing the data, the html source is displayed. Java: Gson gson = new Gson(); String json = gson.toJson(obj); request.setAttribute("gsonData", gson) ...

Utilize data from two distinct JSON sources that are updated at varying intervals, and display the combined results in an ng-repeat

I am currently working on creating a status list that pulls data from two separate JSON sources. The main purpose of this list is to show general information from the first source, while also indicating a status color based on the number of people in the s ...

In JavaScript, the condition can function properly even without the "&&" logical operator, but if the "&&" is included, the condition does not operate

I need the error message to be shown if the character length in the #nameT id is less than 3 or greater than 20. When I use the && logical operator, it does not function correctly, as when the && is not present, it works perfectly when ex ...

AngularJS encounters an issue while attempting to print a PDF file

I am encountering an issue with printing a PDF file that was generated using reportViewer in my Web API. The browser displays an error when attempting to open the PDF file. Below is the code snippet from the controller in my Web API: // ...generate candi ...

Tips on removing previously selected files from a Bootstrap 4 input file

I am currently facing an issue with a form that includes an input file implemented using Bootstrap 4. The functionality of this input file depends on Javascript: when the user clicks on the "browse files" button, a window opens for file selection, and upon ...

Can you tell me the method of checking the number of members in a voice channel?

Is there a method to determine the number of members in a voice channel or check if it's empty using discord.js (V. 13.8.1)? I attempted the following code: async function countMembers(voiceState){ let users = await voiceState.channel.members.siz ...

How to extract hover CSS property from a Selenium WebElement using XPath in Python

Is there a way to detect if a button changes its background color on hover? I know how to get the cursor property: print webElement.value_of_css_property('cursor') But I am unsure how to capture the hover property. ...

Incorporate information into a JSON structure within SAPUI5

While diving into SAPUI5, I decided to challenge myself by creating a basic form. Unfortunately, my attempts are falling short as the new entry I'm trying to add to my JSON model isn't showing up in the file when I run my code. No error messages ...

The text alongside the radio button is not aligned vertically

Hello, I am attempting to vertically align text next to my radio button but encountering some issues. .radio { cursor: pointer; display: inline-flex; } .cui-a-radio-button__input { display: none; } .cui-a-radio-button__input:disabled + .cui-a-rad ...

Avoid losing any entered form information when leaving the page

As I work on creating a datagrid with hundreds of rows, each row features a checkbox that allows users to select items from the grid. I've noticed that users might spend considerable time filtering and searching through the grid, ticking checkboxes a ...

Tips for positioning tables on a page

I have 4 tables and a submit button. How can I make them more compact? Maybe like this: </img> This is my HTML code: <body> <form action="/cgi-bin/form.py" id="myform"> <table class="table-fill"> ... ...

Retrieve an item from an array based on the unique ID value of the button that was clicked using

I am working with a phones array that is populated with JSON data: var phones = [ { "age": 0, "id": "motorola-xoom-with-wi-fi", "imageUrl": "img/phones/motorola-xoom-w ...

The charts created using chartjs-vue display no data

After following some examples to create a test chart, I am facing an issue where the chart renders blank with dummy data. https://i.sstatic.net/RD77S.png My initial suspicion is that maybe the options are not being passed for the lines, but it seems like ...

Executing a function in JavaScript using square brackets

While I was reading through the jQuery source code, I came across this interesting line: jQuery(this)[ state ? "show" : "hide" ](); Is there any particular benefit to using this syntax over the more traditional approach shown below? state ? jQuery(this) ...

Tips for uploading numerous images to Firebase using React Native Fetch Blob

I have a collection of images stored in an array (image paths are stored in the array). I am trying to upload each image using a for loop, but only the last image gets uploaded. My approach involves using React Native Fetch Blob and Firebase for this task. ...

Sending a JS function to a PHP script

I've been incorporating the Soundcloud API into my project and successfully implemented their record button on my website. Once the upload is completed, the code generates the URL of the newly created soundcloud file. My goal now is to pass that URL ...