Toby
Toby

Reputation: 1548

Access the return object from an observable 'synchronously'

Is there a way to access the 'payload' of an observable directly, and have it resolve later, rather than having to subscribe?

For example, I know we can do this..

export class RecordService
{
   fetchRecordFromServer():Observable<Record>
   {
       return http.get().pipe(map(result => return new Record())); // equivalent
   }  
}


export class MyComponent
{
  public record:Record = null;
  constructor(private recordService:RecordService) 
  {
     this.userService.fetchRecordFromServer().subscribe( record => 
     {
        this.record = record;
     }); 
  }
  getRecordName():string
  {
     return this.record? this.record.name || "";
  }
}

I was just wondering if there is a shorthand way to do something like this

export class MyComponent
{
  public record:Observable<Record>;
  constructor(private recordService:RecordService) 
  {
     this.record = this.userService.fetchRecordFromServer();
  }

  getRecordName():string
  {
     return this.record? this.record.name || "";
  }

}

I'm not entirely sure what I am asking, but I think what I'm after is the idea that a value can be assigned from an Observable of type , and will resolve when the Observable fires, and can be treated as if it was an instance of all along.

Maybe promises can do this, or maybe it's a really stupid question. I just feel like I want to say 'set this variable to be an instance of which will be instantiated at some point soon, but you can try to use it safely straight away, and because the observable is of type it will treat it as that type...

Upvotes: 0

Views: 956

Answers (2)

Reactgular
Reactgular

Reputation: 54821

You can use the async pipe in the template so that there is no subscribe usage inside the component.

export class MyComponent
{
    public record$: Observable<Record>;
    constructor(private recordService:RecordService) 
    {
        this.record$ = this.userService.fetchRecordFromServer();
    }

    getRecordName(record: Record):string
    {
        return record ? record.name : "";
    }
}

In the template

   <h1>{{getRecordName(records$ | async)}}</h1>

Upvotes: 1

aaron-bond
aaron-bond

Reputation: 3349

I think by the code you've added that what you're trying to do is tie the UI directly to a hot observable. You can use an Async pipe to do that: https://angular.io/api/common/AsyncPipe

From the documentation:

import { Component } from '@angular/core';
import { Observable, interval } from 'rxjs';
import { map, take } from 'rxjs/operators';

@Component({
  selector: 'app-hero-message',
  template: `
      <h2>Async Hero Message and AsyncPipe</h2>
	    <p>Message: {{ message$ | async }}</p>
	    <button (click)="resend()">Resend</button>`,
})
export class HeroAsyncMessageComponent {
  message$: Observable < string > ;

  private messages = [
    'You are my hero!',
    'You are the best hero!',
    'Will you be my hero?'
  ];

  constructor() {
    this.resend();
  }

  resend() {
    this.message$ = interval(500).pipe(
      map(i => this.messages[i]),
      take(this.messages.length)
    );
  }
}

Upvotes: 1

Related Questions