4

I have a single Service, which returns a single Observable. Now I'm looking for the correct / most efficient way to get multiple results from this Observable without writing too much code.

  • MyService returns an Observable<Array<Foo>>

  • MyComponent calls myService.getFoos() and should output the first 5 elements from the array, and the total length of the array, and the number of elements not shown.

Here's my current code:

@Injectable()
export class MyService {
  foos = new BehaviorSubject<Array<Foo>>([]);

  getFoos() {
    return this.foos.asObservable();
  }
}



@Component({
  template: `
    Total: {{ totalCount | async }}
    Omitted: {{ (totalCount | async) - (maxFiveItems | async).length }}
    <div *ngFor="let item of maxFiveItems | async">
      {{item.bar}}
    </div>
  `
})
export class MyComponent {
  totalCount: Observable<number>;
  maxFiveItems: Observable<Array<Foo>>;

  constructor(myService:MyService) {
    this.totalCount = myService.getFoos()
        .map(arr => arr.length);

    this.maxFiveItems = myService.getFoos()
        .map(arr => arr.slice(0, 5));
  }
}

The result looks fine, but I'm using the async pipe 4 times. Which (as far as I know) will result in 4 Subscriptions. This shouldn't be necessary at all I guess (?)


Of course I could manually subscribe within the constructor of MyComponent and then live without async pipes. But then I have to take care of unsubscribing myself.

Is there any other way to handle this?

Benjamin M
  • 23,599
  • 32
  • 121
  • 201

1 Answers1

4

There's nothing wrong with what you're doing assuming that myService.getFoos() somewhere inside uses share() operator so all your async pipes share the same subscription to the source. If you're using BehaviorSubject as in this example then you're fine.

What you mentioned about subscribing yourself in the constructor is what came to my mind immediately. I don't see manual unsubscription as a problem though.

martin
  • 93,354
  • 25
  • 191
  • 226
  • I don't understang why you should use `share` on a `BehaviorSubject`. Regarding unsubscription, if you manually subscribe to something that can emit more than one value (this is the case for a behavior subject), then you need to unsubscribe. Otherwise you get a memory leak. Basically you would to that implementing the `OnDestroy` interface in your component. – Melou Jan 17 '17 at 17:04
  • Appart from that, I agree with you: @Benjamin approach seems perfectly good. – Melou Jan 17 '17 at 17:06
  • 1
    I just read about an upcoming Feature in Angular 4: **ngIf with async pipe and let** (see: https://netbasal.com/a-taste-from-angular-version-4-50be1c4f3550 ). This could solve some of these multi-subscription scenarios. – Benjamin M Jan 18 '17 at 13:29
  • 1
    Yes, the new `ngIf` would be probably the easiest way to do this. – martin Jan 19 '17 at 07:36