Implementing a Component Overlay Loader With Angular CDK

Be UX-friendly by adding a loader to your components

Silvère Marie
Better Programming

--

In most web applications data is loaded from a server. It can be images, videos, plain text, or any other kind of data. While retrieving that information the user needs to be informed with a visual indicator.

In a previous article called “Implementing a page overlay loader with Angular CDK” we built a service that shows a component on top of the whole page to inform the user and prevent interaction while loading. This approach solves the problem by notifying the user with a loader in the center of the screen. However, it can be annoying for the user because it blocks the interaction with other content.

That is why this article is about adding a loader on top of a component to inform the user and letting the user interact with other components while loading.

Reusing our global loader

For building the new loader we are going to reuse the service we previously built which is responsible for showing and hiding a loader as below.

If you haven’t read the previous article don’t worry it’s recommended but it’s not a requirement. You just have to take a look a the following service and continue reading.

This is the service that we previously build. It is responsible for showing and hiding a page loader by using an overlay provided by Angular Material CDK.

The overlay invokes our LoaderComponent which is a component that encapsulates the CSS loader animation provided by loading.io.

In order to switch from the page overlay to the component overlay we need the reference of the targeted component. One way of doing this is by transforming our service into an attribute directive that will be attached to the targeted component.

For those who don’t know, an attribute directive is an angular concept that “Changes the appearance or behavior of DOM elements and Angular components”. If you want to know more about this topic I suggest reading the official documentation.

Getting component reference

For replacing our service with a directive we must change the angular configuration and replace the @Injectable with @Directive.

Since we move out from a service, we need to declare and export our directive in a Module. We could do it in our AppModule but let’s create a dedicated module in order to avoid having a big and unmaintainable AppModule.

Next, we attach the directive to the component and pass the observable to the directive in order to know when to show and hide the loader.

For example, we will attach the directive to an Angular Material table.

In addition, we should declare the input inside the directive.

Let’s show the loader when the data is requested and subscribe to our observable to know when the data is delivered for hiding the loader.

Now that we are passing the observable to the directive we have two subscriptions. One subscription from the async pipe and another one from our directive. This leads to a double HTTP call, one per subscription.

For mitigating this side effect we can use the RxJs operator ReplaySubject and transform our observable from cold to hot. If you want to dig more into this topic, I suggest reading the article Hot vs Cold Observables by Ben Lesh.

We finally transform our service into a directive. All is working as before and we have the reference of the targeted component for changing the loader position strategy.

Changing the position strategy

Now that we use a directive, we can inject the component reference to change the loader positionStrategy from global to local.

Let’s link the overlay position to the elementRef using the flexibleConnectedTo with the center position. Also, we can remove the hasBackdrop for letting the user interact with the other components.

Congrats! We finally convert our page loader to a component loader.

You can now attach the loader to all components you want and it will render the same!

Fixing the remaining issue

As software developers, we tend to think that it’s finished when we cover the happy path.

However, for producing high-quality software we should think and cover the edge cases. That is why we are going to see how the loader behaves when scrolling.

As you can see when we are scrolling the component is moving but not the loader which is stuck in the initial position. This is not the expected behavior. In fact, the loader should follow the component when it moves.

For solving this issue we can use the scrollStrategy reposition. That means that when we scroll, it will reposition the overlay to fit well with the provided position.

However, this is not enough. If we scroll until our component disappears the loader should be hidden. For that, we can disable the feature named withPush.

The scrolling problem is fixed and our loader works as expected!

If you don’t want to maintain this logic in your app we build ngx-load, a library that does the job for you.

Want to Connect?Follow me on Twitter to read more about Angular!

--

--