1

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>
    
mlbiche
  • 67
  • 2
  • 9
  • 1
    I don't know that one is more efficient than the other. There are different reasons why you might want to use either. Do you want to block the whole ui until both load? Does one take a lot longer than the other to load and you only want to block part of the ui? etc. At the end of the day, you are loading both it seems so I wouldn't imagine one is more efficient than the other. – peinearydevelopment Jun 27 '18 at 15:51
  • are these `Observables` returned by `http` call? – Vikas Jun 27 '18 at 16:55
  • @peinearydevelopment Thank you for your answer ! So it needs to be adapted to the project and the behavior wanted – mlbiche Jun 27 '18 at 21:14
  • @Vikas Yes, they are ! – mlbiche Jun 27 '18 at 21:14

2 Answers2

1

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.

P.S.
  • 15,970
  • 14
  • 62
  • 86
1

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

  1. It will always return the current value on subscription - there is no need to call onnext().
  2. It has a getValue() function to extract the last value as raw data.
  3. It ensures that the component always receives the most recent data.
  4. you can get an observable from behavior subject using the asobservable() method on BehaviorSubject.
  5. 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);


    }

Live Demo

Vikas
  • 11,859
  • 7
  • 45
  • 69
  • Sorry, I haven't been enough precise. My `Observables` are provided by Services returning `http` calls. Your explanation on `Observables` are anyhow interesting. I don't really understand why there is a `subscribe` within the service but I'm really unfamiliar with `Subject` and `BehaviorSubject` as I am still discovering `Observables` _(and have undoubtedly many things to discover)_. Thank you for your presentation of `shareReplay` which appears to be really useful ! – mlbiche Jun 28 '18 at 08:07
  • I finally understood the purpose of `Subject` and `BehaviorSubject`. Those pages help : [`Subject`](https://xgrommx.github.io/rx-book/content/subjects/subject/index.html) and [`BehaviorSubject`](https://xgrommx.github.io/rx-book/content/subjects/behavior_subject/index.html) – mlbiche Jun 28 '18 at 08:14
  • 1
    I have updated my question go through the links to get a clearer picture – Vikas Jun 28 '18 at 09:13