Reputation: 97
Let's imagine we have two models Player
and World
and we want to display a player's information with its world's information within a common view. We get those information through two Observables playerObservable
and worldObvservable
. We define PlayerComponent
(parent), PlayerInformationComponent
(child) and WorldInformationComponent
(child).
I'm wondering which solution is the most efficient :
In PlayerComponent
, I load both player and world information in parallel :
// player.component.ts
forkJoin([playerObservable, worldObservable])
.subscribe(([player, world]) => {
this.player = player;
this.world = world;
});
and provide each information to the corresponding component :
// player.component.html
<app-player [player]="player"></app-player>
<app-world [world]="world"></app-world>
having a ngIf
in each child component :
// player-information.component.html
<div *ngIf="player">...</div>
// world-information.component.html
<div *ngIf="world">...</div>
And an @Input
in each :
// player-information.component.ts
@Input() public player: Player;
// world-information.component.ts
@Input() public world: World;
Each child component load its own information :
// player-information.component.ts
playerObservable.subscribe((player) => { this.player = player; });
// world-information.component.ts
worldObservable.subscribe((world) => { this.world = world; });
And :
// player.component.html
<app-player></app-player>
<app-world></app-world>
Upvotes: 1
Views: 1343
Reputation: 12036
Use services
to share data
Angular distinguishes components from services in order to increase modularity and reusability.
and It's Good Practice to Delegate complex component logic to services
From Angular Style Guide
Do limit logic in a component to only that required for the view. All other logic should be delegated to services.Do move reusable logic to services and keep components simple and focused on their intended purpose.
Why? Logic may be reused by multiple components when placed within a service and exposed via a function.
Why? Logic in a service can more easily be isolated in a unit test, while the calling logic in the component can be easily mocked.
Why? Removes dependencies and hides implementation details from the component.
Why? Keeps the component slim, trim, and focused.
If your objective is to multicast the data use RXJS's Subject
or BehaviorSubject
Subject
acts as a bridge/proxy between the source Observable
and many observers
, making it possible for multiple observers
to share the same Observable
execution.
Advantages of BehaviorSubject
over Subject
onnext().
getValue()
function to extract the last value as raw data.asobservable()
method on BehaviorSubject
.Subject vs BehaviorSubject
Service
private firstResponse=new BehaviorSubject<any>('');
private secondResponse=new BehaviorSubject<any>('');
CurrentDatafirst = this.firstResponse.asObservable();
CurrentDatasecond = this.secondResponse.asObservable();
getdata(){
forkJoin([playerObservable, worldObservable])
.subscribe(([player, world]) => {
this.firstResponse.next(player),
this.secondResponse.next(world)
})
});
}
Component1:
ngOnInit()
{
this.service.CurrentDatafirst.subscribe(//value=>your logic);
this.service.CurrentDatasecond.subscribe(//value=>your logic)
}
Component2:
ngOnInit()
{
this.service.CurrentDatafirst.subscribe(//value=>your logic);
this.service.CurrentDatasecond.subscribe(//value=>your logic)
}
RxJS Subjects for human beings
BehaviorSubject in Angular
Live Demo
-------------------------------------------------------------------------------------
you could also share a single http
request for multiple observers using shareReplay
operator and take action accordingly.
You must be aware of the fact that http
returns a cold observable and
When a cold observable
has multiple subscribers
, the whole data stream is re-emitted for each subscriber
. Each subscriber becomes independent and gets its own stream of data
To Avoid Duplication of HTTP Requests shareReplay
Operator is used.
Service
public response$:Observable<any>
getdata(){
forkJoin([playerObservable, worldObservable]).pipe(sharReplay(1));
}
fetchdata()
{
this.response$;
}
Component1:
ngOnInit()
{
this.service.fetchdata().subscribe(//value=>your logic);
}
Component2:
ngOnInit()
{
this.service.fetchdata().subscribe(//value=>your logic);
}
Upvotes: 1
Reputation: 16394
There is no much difference for your case, I just suggest to decide depending on in which components you need these data, if in parent and children - get in parent and share with child components, if only in child components - you can get data separately right in these children.
BUT
If you have many child components, for example, you repeat something dynamically via *ngFor
, I strongly recommend to get the data in parent component and share with children. Otherwise, you will have, for example 50 components and 50 subscriptions, and it will slow down the app very much.
Upvotes: 1