Async pipe does not fill object data into template

Can anyone help me see if there is a syntax error here in my template? It does not give error, but does not fill in data into the template either:

<div *ngIf="(hero | async)">
  <h2>{{hero}}</h2>
  <h2>{{hero.name}} details!</h2>
  <div>
    <label>_id: </label>{{hero._id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="hero.name" placeholder="name" />
  </div>
  <button (click)="goBack()">Back</button>
</div>

Component code

export class HeroDetailComponent implements OnInit {
    errorMessage: string;

    //@Input() 
    hero: Observable<Hero>;

    constructor(
        private _heroService: HeroService,
        private _routeParams: RouteParams) {
    }

    ngOnInit() {
        let _id = +this._routeParams.get('_id');
        this._heroService.loadHero(_id);
        this.hero = this._heroService.hero$;
        this.hero.subscribe(data => 
           console.log(data)
        )
    }

The console.log(data) prints:

Object {_id: 11, name: “Mr. Nice”}

which means that the data is correctly retrieved.

The <div> block also shows up, which mean *ngIf sees the object as non-empty.

<h2>{{hero}}</h2> shows [object Object].

But why the {{hero.name}} is not showing?

5
Leave a Reply

avatar
5 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Jason Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Jason
Guest

This is now possible using the ‘as’ syntax, available in v4.0.0:

<span *ngIf="user$ | async as user; else loadingUserInfo">
 {{user.firstName}} {{user.lastName}}
</span>
<ng-template #loadingUserInfo>
  Loading user information...
</ng-template>

More details available in the RFC thread on github.

Jason
Guest

I am just adding a precision on how to use the smart / dumb component approach in the case you need to use the async pipe and a bracket syntax.

That combine a trick found here.

< ui-gallery-image([image]="(imagesFB | async) ? (imagesFB | async)[0] : null") ></ui-gallery-image>
Jason
Guest

The best way to handle a Single Observable Object inside an Angular 2.3.x, or Angular 4.x template is to use an async pipe with a template variable. Here’s a common goal for angular developers. Take an array of elements from redux, and pluck a single matching element from the collection. Then render that singular object in a template. COMPONENT @Component({ selector: 'app-document-view', templateUrl: './document-view.component.html', styleUrls: ['./document-view.component.scss'] }) export class DocumentViewComponent implements OnInit { @select(['documents', 'items']) readonly documenList$: Observable<DocumentDTO[]>; public documentVO$: Observable<DocumentDTO>; constructor(private _state: NgRedux<IAppState>, private _route: ActivatedRoute, private _documentActions: DocumentActions) { _route.params.subscribe(params => { let modelId: number = parseInt(params['modelId']); //1… Read more »

Jason
Guest

Objects are a bit tricky with the async pipe. With an Observable that contains an array, we can use NgFor and create a local template variable (hero below) that gets assigned each item of the array after the async pipe extracts the array from the Observable. We can then use that variable elsewhere in the template: <div *ngFor="let hero of heroes | async"> {{hero.name}} </div> <!-- we can't use hero here, outside the NgFor div --> But with an Observable that contains a single object, I’m not aware of any way to create a local template variable that will reference… Read more »

Jason
Guest

Another option would be to use @Input and leverage smart/dumb component approach. In your smart component you can pass the async object to the dumb component then in the dumb component you can use it like a normal object.

The idea is that your smart component deals with logic and data and the dumb component handles presentation.

Smart component:

<dumb-component [myHero]="hero$ | async"></dumb-component>

Dumb component class:

@Input() myHero: Hero;

Dumb component template:

<div>{{ myHero.name }}</div>