DEV Community

Cover image for Scrolling to an Element Only After It Appears using Angular
Fernando Raposo da Camara Silva
Fernando Raposo da Camara Silva

Posted on

Scrolling to an Element Only After It Appears using Angular

This is an evolution of my previous article. 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;
  3. Scroll to the grid only after it was added to the page.

comment: The table 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

1. Button

Let's create a button that will call a fake backend. Let's also add a Spinner just to illustrate time. Here 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>

Enter fullscreen mode Exit fullscreen mode



  1. 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

As it can be seen on Stackblitz, 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

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.

There's also a Stackblitz with this example.

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

Top comments (1)

Collapse
 
bennadel profile image
Ben Nadel

That's a really interesting idea to use the MutationObserver - very clever. I wish that Angular made it easier to do an "after next render" then "do something." I see that in Angular 18, there's an experimental function, afterNextRender(), but it can only run in an Injection context, which isn't broadly helpful. It seems that there is a cow path for setTimeout() - I wish that the Angular team could figure out how to pave that cow path.