How to use Observable with Async pipe inside Angular2 click function
Solution 1
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]);
Solution 2
Just subscribe to the observable in your code, and store the course itself in the component:
this.af.database.object('/bbwLocations/courses/' + courseId)
.subscribe(course => this.course = course);
Then in you view:
<p>{{ course?.description }}</p>
<button ion-button dark full large (click)="openDeckOnBrowser(course?.deckUrl)">
(although I would probably use ng-if and only show the description and the button once the course is available)
Comments
-
Hugh Hou almost 2 years
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?
-
Hugh Hou over 7 yearsWell subscribe to the object defeat the whole point of Firebase Observable project. Using async pipe to optimize the code as it subscribe and unsubscribe when it is done. So it simplify lots of codes for me. With your solution, I will need to unsubscribe when the view destroy and all other cleaning jobs that aysnc pipe could dont for me. I looking for a solution that I don't even need to manually subscribe to the firebase object.
-
Fabian Keller over 7 yearsI just noticed that my latest changes to the Plunker were not saved yesterday. I fixed it and now it should be all correct.
-
Fabian Keller over 7 yearsThe Plunker referenced in the answer works fine with the concepts presented in the answer. I would be glad to help you if you could post your non-working solution in a Plunker, as otherwise I cannot judge where the fault might be located.
-
Jeff almost 7 yearsI used this... and if the item isn't an iterable... you can just wrap it in a
[]
-
rafaelbiten over 6 yearsThis is super nice! The only thing I did to make the whole thing act more like a
*ngIf
was to map it this way instead:.map(i => i ? [i] : undefined)
; On my case, this is anObservable<string>
of an url used in aload more
button. If the Observable getsnothing
, means we should hide the button. This did the trick. -
Kevin Beal over 5 yearsYou couldn't use the async pipe inside of an action even if you wanted to. It's not allowed.
-
Wildhammer almost 5 yearsaction expressions cannot contain pipes