【问题标题】:Angular - Observables combined result multiple callsAngular - Observables 组合结果多次调用
【发布时间】:2019-01-06 04:02:37
【问题描述】:

EDIT 30-07-2018 01:57 CET:仍在寻找以下问题的解决方案:

我有以下代码:

getBoolean(dataRef1, dataRef2) {
  const myFirstObservable = this.af.object(dataRef1).valueChanges();
  const mySecondObservable = this.af.object(dataRef2).valueChanges();

  return combineLatest(myFirstObservable, mySecondObservable).pipe(map(([data1, data2]) => data1 && data2)))
}

代码的基本作用是:它结合两个可观察对象的结果,然后检查每个对象是否返回任何值。如果两个 observable 都有值,则返回 true 否则返回 false

到目前为止一切顺利,一切都按预期工作。然后我从我的视图中调用该方法,为可观察对象提供动态节点引用,并使用布尔值添加条件元素:

<div *ngIf="getBoolean('dataN', 'dataK') | async"> My lovely div content goes here</div>

但是,我的 div 根本不显示在我的视图中。

谁能告诉我我哪里错了,并帮助我达到我想要的结果?

【问题讨论】:

    标签: angular typescript rxjs observable combinelatest


    【解决方案1】:

    问题很可能是您在模板中调用了getBoolean('dataN', 'dataK') 方法。在每次更改检测时,Angular 都会调用 getBoolean 方法,该方法返回一个新的 Observable。旧的已被async 取消订阅,只有新的处于活动状态。

    同时combineLatest 操作员要求所有源 Observables 至少发射一次,这不太可能发生,因为 async 订阅/取消订阅可能在每秒多次发生的任何变化检测周期。

    所以我建议你将 Observable 存储在一个属性中:

    public obs$ = combineLatest(myFirstObservable, mySecondObservable, (data1, data2) => data1 && data2);
    

    那么只在模板中使用obs$ | async

    最终,您可以在getBoolean 中添加一些逻辑来检查obs$ 是否存在,如果存在,您将原样返回。

    【讨论】:

    • 我认为这可能会起作用,但是对于 20 个 observables,我该如何做到这一点?为每对 observables 创建 10 个变量来保存它们的 combineLatest 是不是太过分了?我怎样才能简化这个?
    • @JohnDoe 只需将所有 Observables 添加到数组中并使用combineLatest(array),请参阅github.com/ReactiveX/rxjs/blob/master/src/internal/observable/…
    • 我将所有 observables 存储在一个数组中,并在其上调用 combineLatest。像魅力一样工作。谢谢。
    【解决方案2】:

    getBoolean() 没有返回任何内容。订阅回调中的返回是为订阅返回。一种实现此逻辑的方法。

    getBoolean(dataRef1, dataRef2): Observable<boolean> {
      const myFirstObservable = this.af.object(dataRef1).valueChanges();
      const mySecondObservable = this.af.object(dataRef2).valueChanges();
      return combineLatest(myFirstObservable, mySecondObservable, (data1, data2) => data1 && data2)
    }
    

    还有神奇之处:您使用async 管道link 订阅HTML,它将为您订阅:

    <div *ngIf="getBoolean('dataN', 'dataK') | async"> My lovely div content goes here</div>
    

    【讨论】:

    • 愚蠢的我。确实,这解决了问题!但是,我提供的示例过于简单,因为现在在我的情况下,视图为可观察对象提供了 data1data2 的动态引用。因此,我不能只创建一个布尔值,因为我需要大约 20 个。所以我的问题是:如何从我的视图中直接调用该方法并期望返回一个布尔值?我想避免将值存储在布尔全局变量中。这可能吗?
    • @JohnDoe,你的意思是你有const myNObservable = this.af.object(dataN).valueChanges(); 并想分析其中的任何一个?
    • 是的。所以我的 observables 的节点会改变。所以我不能将结果存储在一个布尔值中并将其放在我的视图中。有没有办法可以返回方法中的值并将其直接用作视图中的条件?例如。 *ngIf="getBoolean('data32', 'data33')"
    • 知道了。我会改变答案。你也可以换个问题吗?也许有人可以帮助这个线程
    • Pedro 和我尝试通过各种方法实现想要的结果,但目前仍然没有成功。也许有人会知道如何达到预期的结果。
    【解决方案3】:

    首先,您的应用程序卡在无限循环中,因为您将视图绑定到一个不返回任何内容的返回函数。此外,我不建议从视图绑定函数,而是绑定到变量。
    您可能会尝试添加一个 BehaviorSubject,它将视图和逻辑绑定到正确的值。
    我制作了一个沙盒来检查它是否有效,并且确实有效。

    TL;DR - 我只是构造了两个 BehaviorSubject 来操纵 第三个,在您的情况下是所需的布尔值。我绑定 通过 combineLatest 将 div 到第三个 BSubject 并且它可以工作。关键是要始终保持一个有效的变量进行绑定,它通过 combineLatest 的订阅得到更新,我通过 BehaviorSubject 更新它的值


    k1 = new BehaviorSubject<boolean>(false);
    k2 = new BehaviorSubject<boolean>(false);
    k3 = new BehaviorSubject<boolean>(false);
    k3$: Observable<boolean>;
    
      constructor() {
        this.k3$ = this.k3.asObservable();
      }
    
      ngOnInit() {
        combineLatest(this.k1.asObservable(), this.k2.asObservable(), (d1, d2) => {
          return d1 && d2;
        }).subscribe(b => {
          console.log(b);
          this.k3.next(b);
        });
      }
    
      toggle1 = () => {
        this.k1.next(true);
      };
      toggle2 = () => {
        this.k2.next(true);
      };
    

    在 HTML 中:

    <div *ngIf='k3$ | async'>
    Example
    </div>
    

    这是可行的,请尝试查看示例并将其投影到您的代码中。 Check the CodeSandbox Example


    祝你好运!

    【讨论】:

      猜你喜欢
      • 2018-08-15
      • 1970-01-01
      • 1970-01-01
      • 2021-02-10
      • 2018-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多