11

I start using ngrx let to using plain objects.

The problem is when I use a lot of observables in my component, I end up with the code which is seems bad (ng-container inside ng-container inside ng-container inside ng-container ...):

<ng-container *ngrxLet="obs1$ as obs1">
 <ng-container *ngrxLet="obs2$ as obs2">
  <ng-container *ngrxLet="obs3$ as obs3">
   <ng-container *ngrxLet="obs4$ as obs4">

    <app-comp [data]="obs1" ..>..</app-comp>
    <app-comp2 [data]="obs1" [data2]="obs3"..>..</app-comp2>
    <app-comp3 [data]="obs1" ..>..</app-comp3>
    <app-comp4 [data]="obs1" ..>..</app-comp4>
    <app-comp5 [data]="obs4" [data11]="obs1" ..>..</app-comp5>
    <app-comp6 [data]="obs2" ..>..</app-comp6>
    <app-comp7 [data]="obs3" ..>..</app-comp7>
  </app-number>
</ng-container>

Is there a better way to handle this syntax?

Jon Sud
  • 10,211
  • 17
  • 76
  • 174

3 Answers3

3
<ng-container *ngrxLet="{obs1: obs1$, obs2: obs2$, obs3: obs3$, obs4: obs4$} as context">
    <app-comp1 [data]="context.obs1" ..>..</app-comp1>
    <app-comp2 [data]="context.obs2" ..>..</app-comp2>
    <app-comp3 [data]="context.obs3" ..>..</app-comp3>
    <app-comp4 [data]="context.obs4" ..>..</app-comp4>
</ng-container>
marvinfrede
  • 1,055
  • 5
  • 12
2

ngrxLet does not seem to support that feature, you could use combineLatest as mentioned in previous answer or try some trcik i used with *ngIf

<ng-container *ngIf="{
  obs1: obs1$ | async,
  obs2: obs2$ | async,
  obs3: obs3$ | async,
  obs4: obs4$ | async
} as data">
    <app-comp [data]="data.obs1"></app-comp>
    <app-comp2 [data]="data.obs1" [data2]="data.obs3"></app-comp2>
    <app-comp3 [data]="data.obs1"></app-comp3>
    <app-comp4 [data]="data.obs1"></app-comp4>
    <app-comp5 [data]="data.obs4" [data11]="data.obs1"></app-comp5>
    <app-comp6 [data]="data.obs2"></app-comp6>
    <app-comp7 [data]="data.obs3"></app-comp7>
</ng-container>
Bulat
  • 138
  • 1
  • 8
1

You could combine the observables in the controller using RxJS functions like combineLatest, zip and forkJoin. Each has a specific mechanism and you could find the differences between them here.

Illustration using combineLatest

Controller

combined$: Observable<any>;

ngOnInit() {
  this.combined$ = combineLatest(
    obs1$.pipe(startWith(null)),
    obs2$.pipe(startWith(null)),
    obs3$.pipe(startWith(null)),
    obs4$.pipe(startWith(null))
  ).map(([obs1, obs2, obs3, obs4]) => ({  // <-- `map` emits a user-friendly object
    obs1: obs1,
    obs2: obs2,
    obs3: obs3,
    obs4: obs4
  }));
}

Template

<ng-container *ngrxLet="combined$ as data">
  <app-comp [data]="data?.obs1" ..>..</app-comp>
  <app-comp2 [data]="data?.obs1" [data2]="data?.obs3"..>..</app-comp2>
  <app-comp3 [data]="data?.obs1" ..>..</app-comp3>
  <app-comp4 [data]="data?.obs1" ..>..</app-comp4>
  <app-comp5 [data]="data?.obs4" [data11]="data?.obs1" ..>..</app-comp5>
  <app-comp6 [data]="data?.obs2" ..>..</app-comp6>
  <app-comp7 [data]="data?.obs3" ..>..</app-comp7>
</ng-container>

However there is a caveat. combineLatest and zip won't start emitting unless each of the source observable has emitted at least once. We can enforce it using the startWith operator like shown here. But then you need to make sure the first value (null here) doesn't affect the data binding. You could of course replace *ngrxLet with *ngIf to avoid emitting the null, but then you'd lose the benefits of *ngrxLet.

ruth
  • 29,535
  • 4
  • 30
  • 57