在模板中使用带有异步管道的 Observable 时显示加载

Posted

技术标签:

【中文标题】在模板中使用带有异步管道的 Observable 时显示加载【英文标题】:Display loading while using Observable with Async pipe in template 【发布时间】:2017-02-12 23:41:30 【问题描述】:

情况:我正在使用 FirebaseObjectObservable 来填充我的 Ionic 2 (rc0) 模板。 模板代码:

<ion-card-content>
  <p>(course | async)?.description</p>
  <br>
  <h2>Learning Objectives</h2>
  <ul>
    <li *ngFor = "let objective of (course | async)?.objectives">objective.text</li>
  </ul>
  <h2>Takeaway</h2>
  <ul>
    <li *ngFor = "let takeaway of (course | async)?.takeaways">takeaway.text</li>
  </ul>
</ion-card-content>

TS 代码:

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

this.course 是一个 Firebase 对象 Observable。一切正常!但是每当我进入模板时,就会出现一闪而过的空无数据。然后所有的数据都跳出来了!对用户体验非常不友好。所以我想使用某种预加载策略。但是由于这里没有 TS 逻辑。一切都通过异步管道在模板级别进行控制。在这种情况下我将如何添加加载?

【问题讨论】:

路由解析器是处理视图先决条件的便捷方式。 路由器解析器是什么意思?我在 Ionic 2 RC0 中。我相信没有路由器。 我不使用 Ionic,但至少 A2 路由器可以实现这一点angular.io/docs/ts/latest/guide/router.html#!#resolve-guard 我不知道 I2 与 A2 路由器的性能有多好。无论如何,处理它的最佳方法是在组件初始化之前解决依赖关系(例如,如果您将其用于导航,则在调用 nav.push 之前)。 【参考方案1】:

你可以这样做:

<style>
  pre 
   color: orange;
   // or whatever you want
  
</style>
<ion-card-content>
  <p>(course | async)?.description</p>
  <br>
  <h2>Learning Objectives</h2>
  <pre *ngIf="!(course | async)">loading objectives...</pre>
  <ul>
    <li *ngFor = "let objective of (course | async)?.objectives">objective.text</li>
  </ul>
  <h2>Takeaway</h2>
  <pre *ngIf="!(course | async)">loading takeaways...</pre>
  <ul>
    <li *ngFor = "let takeaway of (course | async)?.takeaways">takeaway.text</li>
  </ul>
</ion-card-content>

【讨论】:

这行得通。但是如果我想要退出动画,比如当 ngIf 变为 false 时淡出加载器。我将无法做到这一点。另外,是否可以利用可观察对象并为此使用 Ionic Loader 组件? 如果你想使用 ngIf 我相信Animations 是要走的路。您可以使用 ngClass 代替 ngIf 并使用 CSS 制作动画/过渡。 transition: 1s opacity 0.5s linear,诸如此类…… 您能否更新您的解决方案并举例说明如何轻松使用动画来淡出 pre 元素?谢谢! 但这会产生很多不必要的请求... :( 如果它重复了你的请求:你让观察者可以访问一个冷的 observable。您应该使用share() 或类似设置course 作为热可观察对象。 this.course = this.httpClient.get('whatever').pipe(shareReplay(1))。这将存储最新的结果,因此如果您有多个订阅者:他们可以观察结果的重播,而不是发起新的 HTTP 请求。【参考方案2】:

也许有点晚了,但万一其他人想知道如何管理这个...... 使用模板怎么样?

你可以使用类似的东西:

<ion-card-content *ngIf='(course$ | async) as course; else loading'>
  <p>course.description</p>
  <br>
  <h2>Learning Objectives</h2>
  <ul>
     <li *ngFor = "let objective of course.objectives"> 
         objective.text</li>
  </ul>
  <h2>Takeaway</h2>
  <ul>
     <li *ngFor = "let takeaway of course.takeaways"> 
         takeaway.text</li>
  </ul>
</ion-card-content>

<ng-template #loading>
  Loading stuff...
</ng-template>

所以你的 ion-card-content 将被隐藏,显示 #template,直到异步管道被加载。

【讨论】:

【参考方案3】:

假设我们有一个可观察的 meals$。当 observable 被解析(即获取数据)时,我们需要显示加载器。 下面是解决方案。

<div *ngIf="meal$ | async as meal; else loading;" >
   //use the meal variable to show some data
</div>
<ng-template #loading>
   //Show your loader here
</ng-template>

【讨论】:

以上是关于在模板中使用带有异步管道的 Observable 时显示加载的主要内容,如果未能解决你的问题,请参考以下文章

Ionic 4 Angular模板与异步管道绑定到可观察

Angular 5:无法使用异步管道更新模板

在模板中使用异步管道可观察到的不适用于单个值

使用异步管道显示从应用程序状态检索到的 Observable 数据

Angular *ngFor 使用异步管道绑定到 observable - 发生了啥?

从服务返回的 Observable 的单元测试值(使用异步管道)