Ionic4 hide header on scroll - how to hide header on content scroll in Ionic Framework.
Async-Pipe is an Angular built in tool to manage Observable-Subscriptions. We can easily simplify functionality of an Angular code using the async pipe. Letās learn to use Async-Pipe | Observable-Subscriptions.
Async-Pipe manages Observable-Subscriptions, Observables are the type of variables whose values are being tracked whenever changed ā to make sure we always get updated value. We subscribe to an Observable to get its updated value.
Weāll learn to use Async-Pipe:
- With Interpolation Data Binding.
- With different Directives like
*ngIf
and*ngFor
.
Angular Async-Pipe
The angular async pipe āallows the subscription to observe value of anything inside of the angular template syntaxā. It also takes care of unsubscribing from observables automatically.
#1 TO CREATE -> IMPLEMENT āObservableā.
In this example weāll create a component with a very simple observable that increments a value by one in every second and outputs that value.
(Basically this observable is just counting up)
Example-1:
Create a new Component or Open your own component (if you already have one). To create new, run this commandšš
ng g component YourComponentName
Now, open up your ***.component.ts
and update the below codešš
(Make sure to replace HomePageComponent
with your component name. Similarly the name of selector
, templateUrl
and styleUrls
will be replaced by your name.)
import { Component, OnInit } from "@angular/core";
import { Observable } from "rxjs";
@Component({
selector: "app-home",
templateUrl: "./home.page.component.html",
styleUrls: ["./home.page.component.css"],
})
// we must 'implements OnInit' to use 'OnInit'
export class HomePageComponent implements OnInit {
// declare an 'Observable', variable name: 'observableNumber'
observableNumber: Observable<number>;
ngOnInit() {
// create an Observable
this.observableNumber = Observable.create((observer) => {
// initialize value of temp variable 'val' with 0
let val = 0;
const interval = setInterval(() => {
// observer.next will announce the change made in 'val
// by 'observableNumber'
observer.next(val);
// increment value of 'val' after every 1 sec
val++;
}, 1000);
return () => clearInterval(interval);
});
}
}
(We must āimplements OnInitā to use āOnInitā. Learn more -> Click hereš)
#2 TO DISPLAY -> RESOLVE āObservableā.
To display the value weāll reference the observable property and use the async pipe to resolve the observable:
Now, open up your ***.component.html
and add this codešš
<p>{{ observableNumber | async }}</p>
Learn more about Interpolation syntax {{ }} ā> Click hereš)
The output of āobservableNumberā will display the count value on your screen, and increment in every second.
#3 RESOLVE āObservableā ā without using āAsync-Pipeā.
A very common use case of āObservableā is to display values received from a REST-Endpoint/APIs because the Angular HttpClient returns an observable.
Here we will learn to āResolve Observableā returns from āREST-Endpoint/APIsā.
Why we need to use the async pipe?
There are many ways we can subscribe to observables. The default way (without angular) is to subscribe the observable manually and update a separate property with the value, check example below: šš
Example-2:
Open up your ***.component.ts
and update the below codešš
import { Component, OnInit } from "@angular/core";
import { Observable } from "rxjs";
@Component({
selector: "app-home",
templateUrl: "./home.page.component.html",
styleUrls: ["./home.page.component.css"],
})
// we must 'implements OnInit' to use 'OnInit'
export class HomePageComponent implements OnInit {
// create an 'Observable', variable name: 'observableNumber'
observableNumber: Observable<number>;
// create another variable 'latestValue'
// this variable will store the most updated value
latestValue: number;
ngOnInit() {
// create an Observable
this.observableNumber = Observable.create((observer) => {
// THIS IS THE SAME CODE WE USED IN PREVIOUS EXAMPLE-1 TO 'create an Observable'
// initialize value of temp variable 'val' with 0
let val = 0;
const interval = setInterval(() => {
// observer.next will announce the change made in 'val
// by 'observableNumber'
observer.next(val);
// increment value of 'val' after every 1 sec
val++;
}, 1000);
return () => clearInterval(interval);
});
// THIS IS THE NEW CODE
// subscribe to an Observable
// make sure to save a reference to subscription to
// be able to unsubscribe later
this.observableNumber.subscribe((value) => {
// this subscription make sure to have latest value always
this.latestValue = value;
});
// ...
}
}
We can now bind to the property without using the async pipe:
(instead of using āobservableNumberā we are using ālatestValueā to get updated value because we have already āsubscribed observableNumberā in the āngOnInitā function to resolve āObservableā)šš
Now, open up your ***.component.html
and add this codešš
<p>{{ latestValue }}</p>
The output of ālatestValueā will display the count value on your screen ā increment in every second ā same as we see in previous example-1.
So why would we use the async-pipe then?
In Example-2 we subscribed to the observable manually, we also need to manually unsubscribe. Otherwise, we risk a memory leak when the component is destroyed.
To fix this, āwe need to unsubscribe when the component is destroyedā. The best place to do that is the ā ngOnDestroyā lifecycle hook:
Open up your ***.component.ts
and update the below codešš
// import 'OnInit' and 'OnDestroy'
import { Component, OnInit, OnDestroy } from "@angular/core";
// also import 'Subscription'
import { Observable, Subscription } from "rxjs";
@Component({
selector: "app-home",
templateUrl: "./home.page.component.html",
styleUrls: ["./home.page.component.css"],
})
// we must implements 'OnInit' and 'OnDestroy'
export class HomePageComponent implements OnInit, OnDestroy {
// ...
// create a variable to store subscription
subscriptionToObservableNumber: Subscription;
ngOnInit() {
// create an Observable
this.observableNumber = Observable.create((observer) => {
// ...
});
// subscribe to an Observable
// make sure to save a reference to subscription to
// be able to unsubscribe later
this.subscriptionToObservableNumber = this.observableNumber.subscribe(
(value) => {
// this subscription make sure to have latest value always
this.latestValue = value;
}
);
}
// ngOnDestroy executes when component is destroyed
ngOnDestroy() {
// unsubscribe when the component is destroyed
this.subscriptionToObservableNumber.unsubscribe();
}
}
A cleaner and more reactive way of doing the same thing is to use the ārxjs takeUntilā operator with another observable/subject that we complete when the component is destroyed. In this case, the ātakeUntilā operator is taking care of unsubscribing.
Open up your ***.component.ts
and update the below codešš
// import 'OnInit' and 'OnDestroy'
import { Component, OnInit, OnDestroy } from "@angular/core";
// also import 'Subscription'
import { Observable, Subject, Subscription } from "rxjs";
import { takeUntil } from "rxjs/operators";
@Component({
selector: "app-home",
templateUrl: "./home.page.component.html",
styleUrls: ["./home.page.component.css"],
})
// we must implements 'OnInit' and 'OnDestroy'
export class HomePageComponent implements OnInit, OnDestroy {
// create an 'Observable', variable name: 'observableNumber'
observableNumber$: Observable<number>;
// create another variable 'latestValue'
// this variable will store the most updated value
latestValue: number;
// create a variable to store subscription
subscriptionToObservableNumber: Subscription;
// declare unsubscribe$
unsubscribe$: Subject<void> = new Subject<void>();
ngOnInit() {
// create an Observable
this.observableNumber$ = Observable.create((observer) => {
// ...
});
// the 'takeUntil' operator is taking care of unsubscribing
this.observableNumber$
.pipe(takeUntil(this.unsubscribe$))
.subscribe((value) => {
this.latestValue = value;
});
// subscribe to an Observable
// make sure to save a reference to subscription to
// be able to unsubscribe later
this.subscriptionToObservableNumber = this.observableNumber$.subscribe(
(value) => {
// this subscription make sure to have latest value always
this.latestValue = value;
}
);
// create an Observable
this.observableNumber$ = Observable.create((observer) => {
// ...
});
}
// ngOnDestroy executes when component is destroyed
ngOnDestroy() {
// unsubscribe when the component is destroyed
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
}
- This approach is especially useful when dealing with multiple observables per subscription, as we do not need to keep a list with all subscriptions.
- After all, this additional syntax is not necessary when using the angular async pipe, as the pipe itself takes care of unsubscribing from the observable once the component is destroyed. So, if nothing else, the async pipe makes our code cleaner.
- Also, the methods showed above do not work with the onPush change detection strategy, which is used to do performance optimizations of components. Async pipe, on the other hand works just fine with that.
That is why āwe should definitely use the async-pipe wherever and whenever possibleā.
#4 ASYNC-PIPE with *ngIf and *ngFor
With *ngIf
Interpolation {{ }} is not the only data binding to which the async pipe can be used. We can also use it with the *ngIf directive:
Now, open up your ***.component.html
and try this codešš
<p *ngIf="(observableNumber$ | async) > 5">{{ observableNumber$ | async }}</p>
Note, that the braces inside the *ngIf directive are absolutely necessary in this case.
The above
will only be visible when the value of āobservableNumber$ā becomes greater than 5.
With *ngFor
We can use the async pipe for *ngFor the same way we use for *ngIf directive.
But to use the async-pipe we must need the observable of type array, not just a single value. See thisšš
// ...
@Component({
// ...
})
// we must implements 'OnInit' and 'OnDestroy'
export class HomePageComponent implements OnInit, OnDestroy {
// ...
items$: Observable<number[]>;
constructor() {}
}
Now, we can use this in *ngFor directive like thisšš
<p *ngFor="let item of items$ | async">{{ item }}</p>