Home > Back-end >  Using a value from an observable in an Angular Component
Using a value from an observable in an Angular Component

Time:07-18

Typically you would be able to subscribe to an observable:

@Component({
  selector: 'app-my-component',
  template: `<button (click)="someFunction()">Click me!</button>`
})
export class MyComponent {
  aProperty: boolean;

  constructor(private store: Store) {
    this.aProperty = true;
  }

  someFunction() {
    this.store.someObservable$.subscribe((data) => {
      if (this.aProperty && data) {
         // do something
      }
    });
  }

  // unsubscribe from the subscription in OnDestroy

But I've read that it's best avoid to interrupt the 'flow' of a subscription. Also, can I be sure that when calling 'someFunction' it will get the data from someObservable$ at that point in time?

So I was thinking maybe in the lines of:

@Component({
  selector: 'app-my-component',
  template: `<button (click)="someFunction()">Click me!</button>`
})
export class MyComponent {
  aProperty: boolean;
  data = new BehaviorSubject(null);

  constructor(private store: Store) {
    this.store.subscribe(this.data);
    this.aProperty = true;
  }

  someFunction() {
    if (this.aProperty && this.data.getValue()) {
       // do something
    }
  }

  // unsubscribe from the subscription in OnDestroy

What would be the best approach? Since it's a common use-case I'm looking for an idiomatic way of doing this.

CodePudding user response:

I would recommend to use RxJS pipes to deal with unsubscriptions. Let's say you only want to use the first data emitted from your Observable, and only this one, you can use :

someFunction() {
this.store.someObservable$
    .pipe(first())
    .subscribe((data) => {
       if (this.aProperty) {
       // do something
    }
 });
}

This way of doing things ensure the unsubscription from the observable, avoiding you the painfull creation of a subscription and it's unsubscription in the ngOnDestroy().

link to the lib: https://rxjs.dev/api/operators/first

CodePudding user response:

Typically, if we want to use the stream's values inside TS, we subscribe (in ngOnInit for example) and assign to a static value.

data: any;
destroyer$: Subject<void> = new Subject();

ngOnInit() {
    someStream$.pipe(
        takeUntil(this.destroyer$)
    ).subscribe(val => this.data = val);
}

ngOnDestroy() {
    this.destroyer$.next();
}

someFunction() {
    if(this.data) // doSomething();
}

That's a pattern you can use in any project using RxJS, not necessarily an Angular one. More idiomatic is to use the async pipe inside the template, and not bother with subscriptions, cleanup etc., letting Angular elves take care of all that.

<child-component [someInput]="someStream$ | async"></child-component>
  • Related