3

My users can add entries to the bottom of a scrolling list. However, the scrollbar doesn't automatically move down when the entry is added, so the user can't see their newly added entry. How can I keep my scrollbar always in the most scrolled-down position to show the latest entries (using Angular 5)?

ConnorsFan
  • 70,558
  • 13
  • 122
  • 146
FiringBlanks
  • 1,998
  • 4
  • 32
  • 48
  • 1
    you want to automatically scroll down to the most viewed content is it? – Lakindu Gunasekara May 07 '18 at 06:27
  • can you share the code, how your are trying to scroll to the latest entry? – Rajeev Ranjan May 07 '18 at 06:30
  • There are many many many related topics about this if you do a simple search – Carsten May 07 '18 at 06:31
  • Possible duplicate of [Scroll to the top of the page using JavaScript/jQuery?](https://stackoverflow.com/questions/1144805/scroll-to-the-top-of-the-page-using-javascript-jquery) – Carsten May 07 '18 at 06:32
  • Might help you out https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_element_scrollleft – Pardeep Jain May 07 '18 at 06:33
  • I want to scroll down to the *latest* comment (new comments are added to the bottom of the list). However, the scroll bar just stays there. I need it to actually *move down* after the comment is added. – FiringBlanks May 07 '18 at 06:55
  • Here is a general outline of my code: https://plnkr.co/edit/PtgVyRvSJNYV1t7iSxSC?p=preview. The `.comment` code is repeated for each comment in the collection. – FiringBlanks May 07 '18 at 07:02

1 Answers1

11

You can scroll the new entry into view by setting focus on it, as shown in this stackblitz.

  • The item elements can be focused if they have a tabindex attribute
  • They should also have the style attribute outline: none (to remove the focus outline)
  • A template reference variable should be set on the item elements (e.g. #commentDiv)
  • The changes to the list are monitored with ViewChildren and the QueryList.changes event
  • When a change on the list is detected, the focus is set on the last element of the list

HTML:

<textarea [(ngModel)]="newComment"></textarea>
<div>
    <button (click)="addComment()">Add comment to list</button>
</div>
<div>
  Comments
</div>
<div class="list-container">
    <div tabindex="1" #commentDiv class="comment-item" *ngFor="let comment of comments">
        {{ comment }}
    </div>
</div>

CSS:

div.list-container {
  height: 150px; 
  overflow: auto;
  border: solid 1px black;
}

div.comment-item {
  outline: none;
}

Code:

import { Component, ViewChildren, QueryList, ElementRef, AfterViewInit } from '@angular/core';
...    
export class AppComponent {

  @ViewChildren("commentDiv") commentDivs: QueryList<ElementRef>;

  comments = new Array<string>();
  newComment: string = "Default comment content";

  ngAfterViewInit() {
    this.commentDivs.changes.subscribe(() => {
      if (this.commentDivs && this.commentDivs.last) {
        this.commentDivs.last.nativeElement.focus();
      }
    });
  }

  addComment() {
    this.comments.push(this.newComment);
  }
}
ConnorsFan
  • 70,558
  • 13
  • 122
  • 146
  • 2
    I know this is 2 years late and I know this site is bad for kudos posts.... but I want to thank YOU! I have spent almost a week trying to get my chat messages to scroll to the last message and this is the ONLY method which has worked for me. – Adam Feb 08 '20 at 02:25
  • This is a good answer *but* for me `focus()` didn't work, I had to use `scrollIntoView(...)` instead. See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView – Aviad P. May 24 '21 at 17:13
  • @Adam for chats where you want the natural flow of the page to be from bottom to top you could also use flexbox with `flex-direction: column-reverse`. That property was a real lifesaver when i built a chat page last time – Dwagh Sep 29 '21 at 14:14