Scrolling to an Element Only After It Appears using Angular
Tags: angular, html, dom
Published: 2021-07-08 00:51:45

This is an evolution of my previous [article](https://dev.to/ferfox1981/tree-ways-to-scroll-to-an-element-using-angular-1dlj). Let's suppose you have the following requirement:
> In a long page, wait for a specific HTML Element to appear, and **only** after its generation scroll to it.

It looks simple right? But imagine that this Element exibition could take some time, for instance, it could be a grid with some information provided from a web service, or some data from a slow SQL query. Nevertheless, there's no reason to scroll before the data is already shown. So how can we do it? My goals are:
1. Create a button that will generate a grid at the bottom of a long page;
2. After the button is clicked, some mechanism is needed to simulate random time;
4. Scroll to the grid **only** after it was added to the page.

*comment*: The [table](https://www.w3schools.com/html/html_tables.asp) to be scrolled is not added to the page by default. This is possible by using a `*ngIf` statement. As you can see bellow, this is achieved by setting the variable `showTable` to false at startup. This DOM concept is important to understand, because if you have decided to use `hidden` attibute instead of `*ngIf` strategy, the table would be already on your page and DOM, the only thing is that it would be hidden.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4d7uzlll57drnitrjasi.png)
 

#### 1. Button
Let's create a button that will call a fake backend. Let's also add a Spinner just to illustrate time. [Here](https://projects.lukehaas.me/css-loaders/) is a good place where you can find cool CSS Spinners to add to your page.
Bellow you can see that after clicking the button a function named `waitAndGoDown()` is called. This will be described in details next.
```
<div style="text-align: center">
  <button (click)="waitAndGoDown()">Wait Random time and go Down</button>
  <p>
  <div *ngIf="showSpinner" class="loader">Loading...
  </div>
</div>
```
#### 2. Fake Backend
By default, after clicking the button we want to turn the Spinner on and wait some random time until finally exibit the grid. A fake backend can be simulated by using a `setTimeout` method. Look inside `waitAndGoDown()` function:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/55pm6ogqb5fifu29gxka.png)
 
As it can be seen on [Stackblitz](https://stackblitz.com/edit/wait-and-scroll?file=src%2Fapp%2Fapp.component.ts), `simulateBackend()` function uses a random `setTimeout` limited to 5 seconds to randomize the return of the fake Backend. This means that after a while the Spinner is turned off and the grid is allowed to appear.
*comment*: Remember that everything is asynchronous, as a result, the program doesn't wait `simulateBackend` to return to invoke `waitForElement`. That's why there's a need for some mecanism to monitor when the table appears (or when the DOM mutates) and eventually when to scrool to it.

#### 3. Monitoring the Grid
Check bellow how the monitoring is done line by line, notice that the id `'myTable'` of the table to be presented is passed as an argument.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6x8idxac0m9a9pknplx6.png)
 
**Lines 39-43:** Checks if the element is already there. If it is, scroll to it and return.
**Line 44:** Creates an observer that monitors nodes added to the DOM. Every time the DOM mutates, the changes are observed.
**Lines 47-54:** It checks if the newest mutation contains the element we are looking for (the table!). If it is, scroll to it.
**Lines 56-59:** Defines what kind of nodes are going to be observed (the entire childList of the root component)

The function that does the scrolling is one of the options presented [here](https://dev.to/ferfox1981/tree-ways-to-scroll-to-an-element-using-angular-1dlj).

There's also a [Stackblitz](https://stackblitz.com/edit/wait-and-scroll?file=src%2Fapp%2Fapp.component.ts)  with this example. 
{% stackblitz wait-and-scroll %}
Hope this can help someone!

Fonts:
https://projects.lukehaas.me/css-loaders/
https://codepad.co/snippet/wait-for-an-element-to-exist-via-mutation-observer