Navigate to the end of the chat window using AngularJS

Is there a way to automatically scroll to the bottom whenever a new message is received?

I have code that moves the scrollbar, but it doesn't go all the way to the bottom. Can someone please help me with this? Here is my code on Plunker:

http://plnkr.co/edit/NSwZFtmBYZuW7e2iAUq9

This is the HTML snippet:

<!DOCTYPE html>
<html>

<head>
<script data-require="<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c4a5aaa3b1a8a5b6eaaeb784f5eaf7eaf4e9a6a1b0a5eaf1">[email protected]</a>" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>

<body>
<div ng-app="Sojharo">
  <div ng-controller="MyController">
    <div id="chatBox">
      <div ng-repeat="message in messages">
        <div class="chatMessage">
          <div class="messageTextInMessage">{{message.msg}}</div>
        </div>
      </div>
    </div>

    <div class="chatControls">

      <form ng-submit="sendIM(im)">
        <input type="text" ng-model="im.msg" placeholder="Send a message" class="chatTextField" />
      </form>
      Type and press Enter
    </div>
  </div>
</div>
</body>

</html>

This is the JavaScript code:

angular.module('Sojharo', [])

.controller('MyController', function($scope) {

  $scope.messages = [];
  $scope.im = {};

  $scope.sendIM = function(msg) {


    $scope.messages.push(msg);
    $scope.im = {};

    var chatBox = document.getElementById('chatBox');
    chatBox.scrollTop = 300 + 8 + ($scope.messages.length * 240);


  }
});

I would appreciate any suggestions on how to achieve this using AngularJS as well. The method I found online doesn't seem to work either.

Here are some directives that I came across:

.directive("myStream", function(){
   return {        
      restrict: 'A',
      scope:{config:'='},
      link: function(scope, element, attributes){
       //Element is whatever element this "directive" is on
       getUserMedia( {video:true}, function (stream) {
           console.log(stream)
         element.src = URL.createObjectURL(stream);
         //scope.config = {localvideo: element.src};
         //scope.$apply();
       }, function(error){ console.log(error) });
      }
   }

})

.directive('ngFocus', [function() {
      var FOCUS_CLASS = "ng-focused";
      return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attrs, ctrl) {
          ctrl.$focused = false;
          element.bind('focus', function(evt) {
            element.addClass(FOCUS_CLASS);
            scope.$apply(function() {ctrl.$focused = true;});
          }).bind('blur', function(evt) {
            element.removeClass(FOCUS_CLASS);
            scope.$apply(function() {ctrl.$focused = false;});
          });
        }
      }
    }]);

Answer №1

If you want to implement this functionality, consider creating a custom directive:

.directive('scrollBottom', function () {
  return {
    scope: {
      scrollBottom: "="
    },
    link: function (scope, element) {
      scope.$watchCollection('scrollBottom', function (newValue) {
        if (newValue)
        {
          $(element).scrollTop($(element)[0].scrollHeight);
        }
      });
    }
  }
})

For a live example and demo, visit this link.

Remember, it's recommended to avoid direct DOM manipulation within controllers and use directives instead.

Answer №2

Shoutout to @MajoB for the help!

Here are my thoughts on the solution:

  • Eliminated reliance on jQuery
  • Implemented a $timeout to ensure the completion of the $digest cycle

ngScrollBottom.js:

angular.module('myApp').directive('ngScrollBottom', ['$timeout', function ($timeout) {
  return {
    scope: {
      ngScrollBottom: "="
    },
    link: function ($scope, $element) {
      $scope.$watchCollection('ngScrollBottom', function (newValue) {
        if (newValue) {
          $timeout(function(){
            $element.scrollTop($element[0].scrollHeight);
          }, 0);
        }
      });
    }
  }
}]);

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

Tips for creating distinct hover descriptions for each element in an array

My dilemma may not be fully captured by the title I've chosen, but essentially, I am working with a list of names and I want each one to display a unique description when hovered over with a mouse. On the surface, this seems like a simple task, right ...

What is the best way to arrange an array of identical objects based on a specific sub property?

Here's an array of items to work with: myArray = [ { someDate: "2018-01-11T00:00:00", name: "John Smith", level: 5000 }, { someDate: "2017-12-18T00:00:00", name: "Jane Doe", level: 1000 }, { ...

Display stylized portion of text within JavaScript object

I am struggling with formatting a specific part of the text in my Ionic HTML list of cards. The content is populated by objects defined in my JS controller as shown below: <div class="list"> <div class="card" ng-repeat="item in eventsDay19"> ...

Properly extending the functionality of an HTML widget

Understanding HTML and CSS layout is still a mystery to me, so any guidance on what I'm trying to achieve would be greatly appreciated. I am currently developing a JavaScript API for our company's "widget" so that users can integrate it into the ...

What is the best method for effectively eliminating duplicate objects with the same value from an array?

Let's say we have a collection of jqlite objects, and using the angular.equals function, we can determine if they are equal. How can we utilize this function to eliminate duplicate items from an array of jQlite objects? This is my attempted solution: ...

"Angular's ui-router allows for nested views with individual templates and controllers for each

I have the following list of files: index.html car.html truck.html mainCtrl.js carCtrl.js truckCtrl.js I aim to create the following routes: #/search (template: index.html, controller: mainCtrl.js) #/search/car (template: car.html, controller: carCtrl. ...

What methods can be used to block direct attribute updates in a JS/TS class?

class Creature { secretProperty modifySecretProperty(value) { this.secretProperty = value } } new Creature().modifySecretProperty('hidden way') //success new Creature().secretProperty = 'not permitted' // failure To r ...

Surprising Results when Using getBoundingClientRect()

Check out this code on CodePen In my current project, I'm attempting to position the footer div at the bottom of the page in such a way that it aligns with the maximum value of the bottom coordinates of both the menu and content divs (Math.max(menu, ...

The loading sequence of Vuetify CSS for buttons is inconsistent in the production build, leading to functionality problems

I am currently working on a Vue application that utilizes a Vuetify "bottom navigation" component as shown below: <v-bottom-navigation app fixed grow color="#121212" class="bottom-navigation" > <v-btn text tile v-for="menuI ...

What steps do I need to take to build something similar to this using AngularJS?

Struggling with understanding the concepts of AngularJs. How can I create textfields and animations like the ones in this example using AngularJS? I've tried exploring directives, but it's not quite clicking for me. I've attempted to follow ...

Executing an SQL delete query with a button click using a JavaScript function in PHP

I have created a setup with three essential files - index.html, database.php, and function.js. In database.php, there is a form generated containing a delete button that triggers the deletion SQL query when clicked. The primary objective is to present a ta ...

What is preventing me from using CSS to customize elements within InfoWindows?

I've been attempting to adjust the font-size of elements within my InfoWindows, but I'm facing some challenges. Here's a snippet of the code for my InfoWindow: <InfoWindow marker={this.state.activeMarker} visible={thi ...

Guide on establishing a socket connection in the Sails framework version 0.10.5

Attempting to develop a real-time app using Sails.js, I have explored various resources such as YouTube tutorials, the official website for simple solutions, and GitHub repositories for executable examples. Most of the examples I found were based on older ...

Changing the z-index property of a Material-UI <Select> dropdown: What you need to know

Currently, I am implementing an <AppBar> with a significantly high z-index value (using withStyles, it is set to theme.zIndex.modal + 2 which results in 1202). The primary purpose behind this decision is to guarantee that my <Drawer> component ...

Rendering in Three JS involves efficiently utilizing one buffer to display the output within itself

I have been struggling with a particular issue and I really need some assistance: In my three js context, I have created a custom material and rendered it into a texture. ` /* Rendering in texture */ fbo_renderer_scene = new THREE.Scene(); fbo_r ...

Ways to include a notification if the information cannot be retrieved from the backend within 50 seconds (AngularJS)

Hello everyone, I have a question regarding setting a message if the server does not respond within 50 seconds. I am using an AngularJS factory to send requests to the server. $http.post("https://example.com/_ah/api/tweeting/v1/xxx?average_cycle=1&d ...

Unable to load more than one controller in a single partial view using AngularJS

I am having trouble loading a second controller to populate a select in my view. Despite my efforts, it just won't cooperate. This is the code snippet I'm using: app.js (function() { 'use strict'; angular .module('app.lazylo ...

Switching button class when hovering over another div

When you click on the "collapsible-header" div, I want the text "TE LAAT" in the button to change to "NU BETALEN". Currently, the CSS code changes the text on hover, but I want it to change on click when the collapsible-header also has the active class. T ...

Flick user media cards left or right to uncover the following one

I am currently working on creating a widget that will display user media objects in a horizontal layout using ng-repeat. The goal is to allow users to swipe left or right to reveal the next media card, similar to the image shown below. In the example, you ...

Unable to exchange values on the front-end of the next.js app despite the successful operation of the swap function on the back-end

I've built a currency conversion app using next.js and it's running smoothly. However, I'm trying to implement a feature that allows users to easily swap between the From and To currencies. Here is the function code for swapping currencies: ...