【问题标题】:How to show the data of prev observable till the time new observable emit the value如何在新的 observable 发出值之前显示前一个 observable 的数据
【发布时间】:2020-09-14 21:51:30
【问题描述】:

在我的 html 中,我使用异步管道来订阅 observable,如下所示。

<button  (click)="getData(1)" >getUser1</button>
<button style="margin:50px;" (click)="getData(2)" >getUser2</button>
<div>------------------------------------------</div>
<div *ngIf="userData$ |async as user">
data is{{  user | json}}</div>

每当用户点击按钮 1 或 2 时,这个 userData$ 可观察对象就会变成新的。

  getData(id) {

   this.userData$ = this.getDataFromBackend(id);
  }

 getDataFromBackend(id) {
    //delay added to simulate network delay
    // fake backend call but i have to use real one in actual project
  return of(this.dataSource[id]).pipe(delay(1000));
  }

现在,每当用户从 user1 更改为 user2 时,都会分配新的 observable。并且由于这个新的 observable 需要一些时间来获取数据,所以它暂时显示为空。

我们可以做点什么,直到新的可观察数据没有返回,我们才能显示以前的数据。

  I can not user loader here meanwhile.
  I know i can do something like 
  let subject = new Subject();
  let userObservable$ = subject.asObservable()
  and use this observable in the html
  and the subscribe to these observable form getDataFromBackend() here in the class and from 
  subscription do the subject.next() and it will send the updated value
  but this does not seem the best way as it do the manual subscription in the component

下面是 stackblitz 的链接,显示了问题。

https://stackblitz.com/edit/angular-ivy-d9nsxu?file=src%2Fapp%2Fapp.component.ts

【问题讨论】:

  • 为什么不直接创建一个静态变量let user,然后将请求转换为在完成时更新用户的承诺? this.getDataFromBackend(id).toPromise().then( data =&gt; (this.user = data))。不需要异步管道,只需显示用户。

标签: angular rxjs observable angular2-observables rxjs-pipeable-operators


【解决方案1】:

这是一种无需手动订阅的方法:

app.component.ts

export class AppComponent  {

  userData$ :Observable<any>;
  dataSource = {1:{user:'user1', id:1}, 2: {user:'user2', id:2}};

  private userSrc = new Subject<number>();

  ngOnInit () {
    this.userData$ = this.userSrc.pipe(
      startWith(1),
      switchMap(id => this.getDataFromBackend(id)),
    )
  }

  getData(id) {
    this.userSrc.next(id);
  }

  getDataFromBackend(id) {
    return of(this.dataSource[id]).pipe(delay(1000));
  }
}

StackBlitz.

【讨论】:

【解决方案2】:

我会使用以下两个选项之一:

选项 1

您在 DataSource(我猜是服务?)上创建另一个 Observable(loading$state$),它提供布尔指示是否正在加载,或者(甚至更好)“状态”(枚举) 能够指示它是否处于“初始状态”、“已加载”、“正在加载”等。

选项 2

您可以更改流经您的 userData$ Observable 的内容。我建议 Observable 将调解以下数据结构:

{
  user: { ... }, // Containing the user data that has been loaded
  state: "Loaded",
}

(当加载用户数据时),并且:

{
  user: { ... }, // Containing the previously loaded user's data
  state: "Loading",
}

(加载用户数据时)

好吧,老实说 - 我很可能会使用类似 redux 的状态管理系统,例如:

但那是另一回事了

【讨论】:

  • ...如果没有加载用户,JSON 结构(选项 2)的用户条目自然会为 null(或未定义)。
【解决方案3】:

您可以在 *ngIf 块中添加一个 else 块。试试下面的

<div *ngIf="userData$ |async as user; else elseBlock">
  data is {{ user | json }}
</div>
<ng-template #elseBlock>
  Loading...
</ng-template>

我修改了你的Stackblitz

【讨论】:

  • 正如我上面提到的,我不能同时在这里使用加载器。
  • 您可以使用额外的布尔值来解决它。从用户的角度考虑,加载器比显示以前的数据要好。加载程序向用户显示他们的输入已被确认并且正在加载数据。如果旧数据在用户输入后仍然存在,则它们最终可能会不确定并最终导致多次同时点击。
【解决方案4】:

数据消失的原因是因为你立即用一个新的 observable 覆盖了userData$ 对象,它还没有返回结果。

也许您可以订阅getDataFromBackend 调用并在返回结果时覆盖 userData$:

  userData$ = new Subject();
  dataSource = {1:{user:'user1', id:1}, 2: {user:'user2', id:2}};

  getData(id) {
    this.getDataFromBackend(id).subscribe(res => this.userData$.next(res));
  }

【讨论】:

  • 正如我在上一节中提到的,这个手动订阅似乎不是很好的方法,但最后如果我找不到任何方法,那么我想我只会这样做
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
  • 2019-03-01
  • 2018-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多