HTTP Interceptor + Material Progress Loader | The best use case explained in Angular | Service calls
HTML-код
- Опубликовано: 8 сен 2024
- Complete Playlist: • Web Application Develo...
In this video, I explained the best use case/combination of HTTP #interceptor and #angular material progress #loader.
Source Code: github.com/sha...
Closed Captioning:
Have you noticed the loading progress bar in youtube, at the top when a communication is happening in the background?
Have you noticed this loading spinner before the video starts playing?
In this video, we will add a progress bar and spinner for our application.
For that, first we will add the Material Progress Bar module in the app module file.
Now, open the nav components HTML file.
In the main contents section, we will add a div, inside which we will place the material progress bar.
The material progress bar can be of different types.
Determinate requires a input value to display the progress.
Indeterminate does not require any input. It simply displays the loader.
Buffer type requires input values for buffer and progress.
Query type does not require any input. It displays the animation backward.
We will use the indeterminate mode.
Let's run the application and see.
This is how it will look like.
Since this needs to be displayed in front of everything else whenever network calls happen,
we must add some CSS styling to it.
Let's add the css class for progress bar's container div.
Open the CSS file and define the classes here.
The container must have position fixed. This will keep the div fixed at the top.
set width to 100%, so that the entire loader will be visible.
set z-index greater than 1.
z-index value determines where the div will be placed in the stack of HTML elements.
Higher index value makes sure that the div is at the front.
Let's keep it as 99.
Before moving on, we will just add a default route to our application.
Open the app routing module file, and add this path to the routes array.
From now on, every time a unknown path is detected, the application will be redirected to the home route.
For that we need to implement HTTP Interceptor in Angular.
An Http Interceptor can know about, each and every Http request calls happening in the application.
When a Http request starts or completes, the interceptor will inform us.
In our project, we will first create a folder named 'loader'.
Open the folder in terminal, and create service named 'loader'.
Here we will create a public variable, of type BehaviorSubject with initial value 'false'.
Our material progress bar will be displayed based its value.
If it is true, progress bar will be shown, else hidden.
We must inject this service in our nav component.
And use the public variable 'is loading', in the ngIf directive.
Since this is a Observable type variable, we must add the async pipe here.
The progress bar is not displayed because the initial value of 'is loading' is false.
If it is set to true, the loader will be displayed.
To set its value, we will add an interceptor to know when an API call is happening, and when the API call is getting completed.
Create one more service named 'interceptor'.
This service must implement HttpInterceptor.
An error will be displayed which asks us to override the required 'intercept' method.
intercept is the method which will be invoked everytime a Http call is detected.
Inside this method, we will update the boolean value of 'is loading'.
Let's inject the loader service here.
In the intercept method, first we will set the variable to true. so that the loader will be visible.
Since this is a Behavior Subject, we must call the 'next' method to update the value.
After that, we must return the next handle to complete the API call.
Also, we need to check for the completion of API call, to hide the loader.
For that, we must pipe the request, and use the finalize method to hide the loader at last.
The finalize method will be invoked even if the request terminates due to any errors.
Inside the finalize method, we will update the value of 'is loading' to false.
For the Http interceptor to work, we must add it in the providers section of app module, Like this.
Http Interceptor requires the 'multi' property to be true.
That worked perfectly, but so quickly.
For testing, let's add a timer in the express JS server.
In the deals router file, we will add a timeout of 3 seconds.
We shall move our code to the timout callback.
Now, let's run the application and see.
As we can see, the application is showing the loader when the API call is happening.
For that, first we must use the material progress spinner module in the app module file.
In the HTML file, we must delete the progress bar and use the material spinner.
The spinner is hardly visible.
Let's make some changes to the CSS.
In the loader container class,
change the position type to absolute.
set height to 100 percent.
set the background color to black, and opacity to 0.8
And for the material spinner element, add the style attributes top and left.
Both 50 percent.
Run the application
For those facing the issue with multiple parallel requests. This ensures the loader isn't set to false until all requests are completed:
@Injectable()
export class LoaderInterceptor implements HttpInterceptor {
private count = 0;
constructor(private loaderService: LoaderService) {}
intercept(request: HttpRequest, next: HttpHandler): Observable {
this.loaderService.isLoading.next(true);
this.count++;
return next.handle(request).pipe(
finalize(() => {
this.count--;
if (this.count === 0) {
this.loaderService.isLoading.next(false);
}
})
);
}
}
The best angular video thar I've ever seen!! Watching all them...
thank you so much for your feedback.. 😊
Master!!! Very nice and crystal clear explanation, thank u for sharing your knowledge.
Glad it was helpful!😊
Gracias por compartir tus conocimientos, Thank you for sharing your knowledges
far far better then anyone easy to understand to the point
Thank you for sharing! I’m definitely subscribing to you after watching this video. You explained everything very well. Thank you and keep it up!
Awesome! Thank you!😊
Worked like a charm in 15min. Thank you!
Clear and easy to understand, thanks so much, I'll watch your content more often from now on.
Thanks i need implement this characteristcs and it worked
Thank you very much this was the thing I was searching for😁❤👌😊😍!!
thank you very much for this solution. except when tiny problem with it, when debuggin the app it shows this ExpressionChangedAfterItHasBeenCheckedError error
Keep the videos coming, this is great and much better explained than others
Big information at small time, Thanks a lot
Nicely explained and works with Angular 11 as well, Subscribing the channel right away.
this is very useful for my application development sir
Very good tutorials! Cheers man!
Thanku Sir ...For The video! 👌
Most welcome 😊.. glad you like it!
Thanks for the help!
this is great even explaining the small details
working...super
thanks
it works perfect thank you so much
Thank you, very perfectly tutorial and simple understand!
Thank you so much! Perfect tutorial
Glad you liked it!😊
You make my day better. Thanks!
that was great thanks
Thank you, clear and easy understand
Thank you so much for logic for spinner
Wow Sir you are genius thankssss
Thank you so much!
You are so great! Just Wow thaaanks
Hi, Thx for the video, really helpfull, could you make more angular videos, !, really well explained.
Very nice vidoe. I loved it
Thank you so much daya 😀
very very thank you, how easily explain
Thanks , but It does not work with multiple parallel http requests
Great video! Thanks!
Best of the best
Hi,
Thanks for this video, I just have a question : how can we do to call that the interceptor just when we load the data?
the interceptor will be called in any http call in and out of the app
Thanks man, you're the best
Thank you
very helpful thanks
Excelent video!
Super Video
Thanks 🙂
Great tutorial, Thanks for sharing.
But I am getting : "NG0100: Expression has changed after it was checked" error in the console. How can I fix this?
me too
Great video!!!!
its work but I get error Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'
awesome, thank you
Beautiful
Thank you! Cheers! 😊
Ohhh sorry ...tqs anyway👍👍👍...nice video👍👍👍
Hi Aishwarya, here's the link
github.com/shaheershukur/Market-Web-Application
*btw it was already mentioned in the video description 😊
Thank you!
I loaded 10000+ data rows, however api time is finish in 2.79s with interceptor however dev tools network tab, the API preview data is not load actually, need to wait for around 10s+ and page freeze. Any idea?
Thank you It's very cool, Can you make dark them tutorial ?
I believe it's already present at 7:49 . However, you may also take a look at this ruclips.net/video/r6Ygw9L55zg/видео.html
thank you :)
thanks :)
✌👌
Thanks 😊
Hii, How to set a value from 0 to 100 in the progress-bar when waiting for the request to finish?
I don't think this is the exact behavior that RUclips implemented because I notice that RUclips shows the progress bar while fetching data for the next route and as soon as all data is fetched, the progress bar disappears then new view (component) along with its data shows up
How to implement loader for websocket url call through this interceptor concept?
Sir which text to speech software you are using in your video ?
Hi abdulla, im using animaker voice web app for TTS
@@shaheershukur thanks bro ❤️
It works but I am getting this Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError
i have the same error
I'm encountering the same error. Anyone solved it?
I encountered the same error.
I figure that HTML doesnt really like observables in an *ngIF statement as it gets confused on what to do.
Instead how i fixed it is to bind it to hidden.
Example:
x.component.html:
Loading data ...
interceptor.service.ts:
export class InterceptorService implements HttpInterceptor {
constructor(public loaderService: LoaderService) {}
count = 0;
intercept(
req: HttpRequest,
next: HttpHandler
): Observable {
if (this.count === 0) {
this.loaderService.isLoading.next(true);
// To only submit the value of true to the isLoading observable once, instead of spamming it with true
}
this.count++;
// Increments count by 1 for each http request
return next.handle(req).pipe(
finalize(() => {
this.count--;
// substract the count for each http req that has been fullfilled
// if count is 0 then all reqs have been fullfilled and isLoading wont go to false to early
if (this.count === 0) {
this.loaderService.isLoading.next(false);
}
})
);
}
}
@@insomniety use OnInit hook when initialize your observable variable
I'm getting ERROR in console: core.mjs:7635 ERROR Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'.🤥
You need add in your constructor "private cdref: ChangeDetectorRef"
Then add: ngAfterContentChecked() {
this.cdref.detectChanges();
}
does it work when we have multiple api calls when a page loads
Yes.. that is the main reason we use interceptor, to tap each and every requests. In this example, Interceptor will update the BehaviorSubjects value(which in turn hides and unhides the loader) even for multiple api calls.
@@shaheershukur but if an api call finishes early, before another call in the same page, which will result in turning off the loader before the second call completes. right?
Ok, now I got you.. In case there are multiple service calls to be made in a single page itself, we may consider adding a counter variable in the interceptor service. Whenever service call(multiple) starts, increment it.. And inside the finalize() method, decrement the count.. at last, IF AND ONLY IF the counter has value 0, turn off the loader.... I believe that can solve the issue.
@@shaheershukur Thanks👍
@jobin thank you so much for this question.. it may help other too.. 👍😊
malayali anno ....
haa athe..😄
Polii
Thank you so much!