当前位置: 首页 > 知识库问答 >
问题:

可观测阵列上的rxjs CombineTest和Anguar2变化检测

桑思远
2023-03-14

在我的应用程序中,我一直在努力进行一些基本的更改检测。我已经这样做了几天了,而且失去了意志!我想知道这里是否有人能给我指出正确的方向。

我有一个和2个用户列表。一个是给成员的,另一个是给主持人的

此方法连接到数据库以获取对象列表,每个对象都有一个$key值。现在我想使用这些键去获取每个用户的实际UserData。我什么都试过了,combinelateest似乎是我唯一能工作的东西。

因此,两者都调用函数,我在模板上使用async管道。

members$ = myService.getMemberListByType("blah", "members");
moderators$ = myService.getMemberListByType("blah", "moderators");

我的函数是这样的。

  private getMemberListByType(groupKey: string, memberType: string) {

    return this.af.database.list(`groups/${groupKey}/${memberType}`)
      .switchMap(userListKeyMap => {

        console.log("UserListKeyMap", memberType, userListKeyMap);

        let usersObservables: Observable<UserData>[] = [];
        userListKeyMap.forEach((object) => {
          usersObservables.push(this.af.database.object(`users/${object.$key}`)
            .map(UserData.fromJSON));
        });

        return Observable.combineLatest(usersObservables);
      });

  }

但是,Angular不会检测到此列表的更改,如下所示。假设其他地方使用不同的方法删除成员,并将其添加到主持人。在这种情况下,成员列表发出一个空的用户列表[]

My*ngIf和*ngFor无法检测此新空对象的更改。结果是,用户(在模板上)现在是2个列表的一部分,但此列表下的数据非常准确,如日志中突出显示的那样。

我觉得当我在一个空数组上组合最新时,这就是我问题的根源。没有东西可以发射......那么Angular是如何改变的呢?我不知道如何解决它。在这个“空”用例中,有没有组合最新的替代方案?因为我正在使用一个async管道,所以我需要一些有意义的东西。

有谁能对我的问题有所了解吗?

非常感谢。

使现代化

我确信问题在于angular2没有检测到一个空的可观察列表。特别是当一个可观察数组有一个值,但后来该值变为空时。Angular2将看不到空数组。我现在没有办法解决这个问题。要么我的方法是错误的,要么某个特定的事件需要注册一个空的可观察列表?

  1. Blue=组件的加载状态良好,用户是成员。
  2. Green=用户从成员移动到经理/主持人。
  3. Red=这是不存在的,那么为什么它还在显示?

共有3个答案

林星华
2023-03-14

您应该尝试以下方法:

private getMemberListByType(groupKey: string, memberType: string) {

  return this.af.database.list(`groups/${groupKey}/${memberType}`)

           // Force the source obs to complete to let .toArray() do its job.
           .take(1)

           // At this point, the obs emits a SINGLE array of ALL users.
           .do(userList => console.log(userList))

           // This "flattens" the array of users and emits each user individually.
           .mergeMap(val => val)

           // At this point, the obs emits ONE user at a time.
           .do(user => console.log(user))

           // Load the current user
           .mergeMap(user => this.af.database.object(`users/${user.$key}`))

           // At this point, the obs emits ONE loaded user at a time.
           .do(userData => console.log(userData))

           // Transform the raw user data into a User object.
           .map(userData => User.fromJSON(userData))

           // Store all user objects into a SINGLE, final array.
           .toArray();

}

笔记以do()开头的行仅用于解释发生了什么。无需将它们保留在最终代码中。

辛龙野
2023-03-14

你的方法在我看来是正确的。使用空数组组合最新()不应该以错误结束(类似于例如。forkJoin,使用空数组是一个有效的用例)。然后,即使它完成了,因为一个空数组,你正在使用SwitchMap,所以这不应该是我认为的问题。

我对AngularFire2没有任何经验,所以我不知道this.af.database.object是否只发出所有项目一次,然后完成,或者它在每次更改时都会发出一个值(如果我猜的话,这可能是你想要的)。

无论如何,使用combineLatest()forkJoin()的一个非常常见的问题是,它们的源观测值总是必须发出至少一个项。换句话说,如果this.af.database.object中的任何一个是空的,那么combinelatetest()将不会发出任何东西。

您可以使用startWith()确保始终至少有一个值。例如,如下所示:

userListKeyMap.forEach((object) => {
    usersObservables.push(this.af.database.object(`users/${object.$key}`)
        .startWith('{}')
        .map(UserData.fromJSON));
});

如果这没有帮助,请尝试使用Observable.timer()而不是this.af.database.objectthis.af.database.list,以确保Angular2订阅了它,并在发出新项目时保留订阅。

公羊涛
2023-03-14

有一个简单的解决方法:

  private getMemberListByType(groupKey: string, memberType: string) {

    return this.af.database.list(`groups/${groupKey}/${memberType}`)
      .switchMap(userListKeyMap => {

        console.log("UserListKeyMap", memberType, userListKeyMap);

        let usersObservables: Observable<UserData>[] = [];
        userListKeyMap.forEach((object) => {
          usersObservables.push(this.af.database.object(`users/${object.$key}`)
            .map(UserData.fromJSON));
        });

        return usersObservables.length > 0 ? Observable.combineLatest(usersObservables) : Observable.of([]);
      });
 }
 类似资料:
  • 我正在使用angularfire,我得到了一个连续的阵列流,其中包含任务ID。我需要获取数组中每个id的任务文档作为一个新的可观察的。然后将任务文档数组返回到流中,这样我就可以在组件中订阅它并显示任务列表。 到目前为止,我用mergeMap得到了它。我分割阵列,获取任务文档并将它们返回到流中。我的解决方案唯一的问题是,当我订阅可观察到的时,我没有得到一系列任务,但每个任务都是一个单一的变化,我不能

  • 问题内容: 在Javascript中,当使用基于推,弹出,移位或基于索引的分配修改数组时,是否有通知方法?我想要能够触发我可以处理的事件的东西。 我知道SpiderMonkey 的功能,但是仅当整个变量设置为其他值时,该功能才起作用。 问题答案: 有一些选择… 1.覆盖推送方法 走快速而肮脏的路线,您可以覆盖数组1的方法: 1或者,如果要定位 所有 数组,则可以覆盖。但是要小心;您环境中的其他代码

  • 问题内容: 我有一个使用ajax请求检索对象数组的父组件。 该组件有两个子组件:一个子组件以树结构显示对象,另一个子组件以表格格式呈现其内容。父级通过@input属性将数组传递给其子级,它们会正确显示内容。一切都如预期。 当您更改对象内的某些字段时,会发生问题:子组件不会收到有关这些更改的通知。仅当您手动将数组重新分配给它的变量时,才会触发更改。 我已经习惯了使用Knockout JS,并且需要获

  • Figure: Change Detector by Vovka is licensed under Public Domain () 变化检测在旧版本的Angular和新版本之间发生了很大的变化。在Angular 1中,框架保留了一长串观察者(每个属性绑定到我们的模板),需要在每次 digest 循环开始时检查。这被称为脏检查,它是唯一可用的变化检测机制。 在Angular 2中,信息流是单向的

  • 由于双向数据绑定的本质,在Angular 1中不能保证父节点在子节点之前总是被检查。 有可能子节点可以改变父节点或兄弟节点或树中的任何其他节点,这又会在链中触发新的更新。 这使得变化检测机制难以遍历所有节点,并可能掉入具有臭名昭着的“震荡”循环中: 在Angular 2中,改变被保证单向传播。 更改检测器将遍历每个节点一次,始终从根开始。 这意味着父组件始终在其子组件之前检查。

  • 我们将创建一个简单的来显示一个电影的信息。 这个应用程序将只包含两个组件:MovieComponent显示有关电影的信息和MainComponent,它使用按钮来保存对电影的引用以执行一些动作。 我们的AppComponent组件将有三个属性:应用程序的slogan,电影的title(标题)和(主角)。 最后两个属性将被传递到模板中引用的MovieComponent元素。 在上面的代码片段中,我们