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?
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With