Robbie Mills
Robbie Mills

Reputation: 2945

Angular scrolling to dynamically created element

I have an Angular application where I retrieve data when the user clicks a button:

getJobNotes() {
  this.jobNoteService.getJobNotes()
    .subscribe(
      result => {
        this.jobNotes = result.jobNotes;
      }
    );
}

I would like to scroll into view an element that has a specific job note Id, ie, this may be the 5th element in a list of 10 as an example.

I have tried the following:

  this.selectedJobNoteId = result.selectedJobNoteId;
  let el = document.getElementById(this.selectedJobNoteId);
  el.scrollIntoView();

in this case my 'el' variable is undefined.

In my html I am setting the ID correctly:

<li *ngFor="let jobNote of jobNotes" id="{{jobNote.jobNoteId}}">

I have confirmed that the ID is set, and if I run document.getElementById with the correct ID in the chrome console then I get back the element - I suspect the issue is that the elements are dynamically created?

Upvotes: 1

Views: 2483

Answers (1)

SiddAjmera
SiddAjmera

Reputation: 39432

You could assign a template variable to the list item:

<ul *ngIf="users">
  <li #user *ngFor="let userDetail of users">
    <h1>{{ userDetail.name }}</h1>
    <h2>{{ userDetail.username }}</h2>
    <h3>{{ userDetail.email }}</h3>
  </li>
</ul>

And then in the Component class, you could access the list-items using ViewChildren. Something like this:

@ViewChildren("user", { read: ElementRef }) renderedUsers: QueryList<ElementRef>;

And then finally, you could use scrollIntoView on a nativeElement of any item to scroll to it:

getData() {
  this.http
    .get("https://jsonplaceholder.typicode.com/users")
    .subscribe(users => {
      this.users = users;
      this.timeoutId = setTimeout(() => {
        const userToScrollOn = this.renderedUsers.toArray();
        userToScrollOn[this.indexToScrollTo].nativeElement.scrollIntoView({
          behavior: 'smooth'
        });
      }, 1000);
    });
}

I've used a setTimeout here coz, the list won't render as soon as you get the data. So there would be a slight delay before renderedUsers is initialized.

So in ngOnDestroy also make sure to clear the timeout by calling clearTimeout(this.timeoutId);


Here's a Working Sample Demo 🚀 for your ref.

Upvotes: 1

Related Questions