简体   繁体   English

如何在Angular2单击函数中使用带有异步管道的Observable

[英]How to use Observable with Async pipe inside Angular2 click function

Situation: I am using FirebaseObjectObservable to populate my Ionic 2 (rc0) template. 情况:我正在使用FirebaseObjectObservable来填充我的Ionic 2(rc0)模板。 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 TS文件是

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

this.course is a Firebase Object Observable. this.course是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. 问题是,这部分不起作用:( click)=“openDeckOnBrowser(course.deckUrl)。由于course.deckUrl为空。我无法将值传递给函数。

Tho only hacky way I found to work around so far is this: 到目前为止,我发现只能使用hacky方式:

 <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? 但任何官方和更容易的方法来解决这个问题?

In your template (click)="openDeckOnBrowser(course.deckUrl)" is evaluated as soon as the template is parsed. 在您的模板中(click)="openDeckOnBrowser(course.deckUrl)"将在解析模板后立即进行评估。 You do not use the async pipe here, hence the deckUrl is empty. 您不在此处使用异步管道,因此deckUrl为空。 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. AsyncPipe上的官方文档始终使用*ngFor输出项目列表而不输出*ngIf来输出单个项目。 The reason is simple: the *ngIf directive does not allow any assignments. 原因很简单: *ngIf指令不允许任何赋值。 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 参见Plunker的工作演示

Just subscribe to the observable in your code, and store the course itself in the component: 只需订阅代码中的observable,并将课程本身存储在组件中:

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) (虽然我可能会使用ng-if并且仅在课程可用时显示说明和按钮)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM