Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Observable with Async pipe inside Angular2 click function

Situation: I am using FirebaseObjectObservable to populate my Ionic 2 (rc0) template. Template code:

 <p>{{(course | async)?.description}}</p>
 <button ion-button dark full large (click)="openDeckOnBrowser(course.deckUrl)">
  <ion-icon name='cloud-download'></ion-icon>
  <div>View Deck</div>
 </button>

The TS file is

  this.course = this.af.database.object('/bbwLocations/courses/' + courseId); 

this.course is a Firebase Object Observable. The problem is, this part won't work: (click)="openDeckOnBrowser(course.deckUrl). As the course.deckUrl is empty. I can not pass the value to the function.

Tho only hacky way I found to work around so far is this:

 <button id="{{(course | async)?.deckUrl}}" ion-button dark full large (click)="openDeckOnBrowser($event)">
  <ion-icon name='cloud-download'></ion-icon>
  <div id="{{(course | async)?.deckUrl}}">View Deck</div>
</button>

And on the click event:

  openDeckOnBrowser(event):void {
    console.log(event);
    let target = event.target || event.srcElement || event.currentTarget;
    let idAttr = target.attributes.id;
    let url = idAttr.nodeValue;
    console.log (url);
   }

But any official and easier way to approach this?

like image 478
Hugh Hou Avatar asked Oct 04 '16 19:10

Hugh Hou


People also ask

How do you use async pipe in component?

Angular's async pipe is a pipe that subscribes to an Observable or Promise for you and returns the last value that was emitted. $observable. subscribe((result) => { // do something with the result here }); Every time a new value is emitted the async pipe will automatically mark your component to be checked for changes.

How do you use async pipe?

The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted. When a new value is emitted, the async pipe marks the component to be checked for changes. When the component gets destroyed, the async pipe unsubscribes automatically to avoid potential memory leaks.

Can we use async pipe in NgFor?

NgFor has a not-so-obvious feature that lets us will help us deal with asynchronous operations - the async pipe. The async pipe takes care of subscribing/unsubscribing to Observable streams for us.

What type of data works with async pipe in angular?

We can use the async pipe in Angular application by including the CommonModule which exports all the basic Angular directives and pipes, such as NgIf, NgForOf, DecimalPipe, and so on.


1 Answers

In your template (click)="openDeckOnBrowser(course.deckUrl)" is evaluated as soon as the template is parsed. You do not use the async pipe here, hence the deckUrl is empty. You can fix this by adding a second async pipe:

<p>{{(course|async)?.description}}</p>
<button ... (click)="openDeckOnBrowser((course|async).deckUrl)">...</button>

However, this is not nice as two subscriptions will be created.

A (better) alternative:

The official docs on the AsyncPipe always use *ngFor to output a list of items and not *ngIf to output a single item. The reason is simple: the *ngIf directive does not allow any assignments. But we can work around this limitation:

The template looks as follows:

<div *ngFor="let course of course$|async">
    <p>Course: {{course?.name}}</p>
    <p>Url: {{course?.url}}</p>
</div>

And in the component, we'll just map the course to a list of a single course:

this.getCourse().map(c=>[c]);

See working Demo in Plunker

like image 157
Fabian Keller Avatar answered Oct 13 '22 19:10

Fabian Keller