Kevin Malone
Kevin Malone

Reputation: 109

How to subscribe to an Observable in Angular

I'm trying to subscribe to an Observable so I can display it in HTML with Angular, doing console.log(player) works fine however I get

Type 'Player' is missing the following properties from type 'Observable<Player>': _isScalar, source, operator, lift, and 6 more.ts(2740)

I've tried using .pipe(),

HTML:

<div *ngIf="(player$ | async) as player">
  <div *ngIf="player.characterUid">
    {{player.characterName}}
  </div>
</div>

Component:

player$: Observable<Player>;
subPlayer: Subscription;

selectPlayer(matEvent: MatAutocompleteSelectedEvent): void {
    this.inputFriends = matEvent.option.value;
    this.selectedPlayer = matEvent.option.value;
    this.inputP = false;

    this.subPlayer = this.playerProvider.get$(matEvent.option.value.userUid).subscribe(
      (player: Player) => {
        this.player$ = player; // Type 'Player' is missing the following properties from type 'Observable<Player>': _isScalar, source, operator, lift, and 6 more.ts(2740)
      }
    );
  }

Provider:

get$(uid: string): Observable<Player> {
    return this._getDoc(uid)
      .valueChanges()
      .pipe(
        map((sPlayer: ServerPlayer) => sPlayer ? new Player(sPlayer) : null)
      );
  }

  private _getDoc(uid: string): AngularFirestoreDocument {
    return this.afs.doc(`players/${uid}`);
  }

I'm just trying to assign player$ so I can display it in the HTML

Upvotes: 2

Views: 1272

Answers (3)

Muhammed Albarmavi
Muhammed Albarmavi

Reputation: 24406

you don't need to subscribe , async pipe will subscribe and get the value for you 🧙‍♂️

player$: Observable<Player>;

selectPlayer(matEvent: MatAutocompleteSelectedEvent): void {
    this.inputFriends = matEvent.option.value;
    this.selectedPlayer = matEvent.option.value;
    this.inputP = false;

    this.player$= this.playerProvider.get$(matEvent.option.value.userUid);

  }

The async pipe takes care of subscribing and unwrapping the data as well as unsubscribing when the component is destroyed, so you don't need subPlayer

template

<ng-container *ngIf="(player$ | async) as player">
  <div *ngIf="player.characterUid">
    {{player.characterName}}
  </div>
</ng-container>

Async Pipe 🔥

Upvotes: 2

Florian
Florian

Reputation: 1481

I'm just trying to assign player$ so I can display it in the HTML

this.player$ = this.playerProvider.get$(matEvent.option.value.userUid);

this method returns an observable, so if you want to assign player$, you can do it that way. In your html template, you're using | async which handles subscribe/unsubscribe automagically.

Upvotes: 1

Morphyish
Morphyish

Reputation: 4062

In your code player$ is not an observable, it's already the result of the observable.

player: Player; // <-- here
subPlayer: Subscription;

selectPlayer(matEvent: MatAutocompleteSelectedEvent): void {
    this.inputFriends = matEvent.option.value;
    this.selectedPlayer = matEvent.option.value;
    this.inputP = false;

    this.subPlayer = this.playerProvider.get$(matEvent.option.value.userUid).subscribe(
      (player: Player) => {
        this.player = player; // <-- here
      }
    );
  }
<div *ngIf="player"> <!-- here -->
  <div *ngIf="player.characterUid">
    {{player.characterName}}
  </div>
</div>

Upvotes: 1

Related Questions