【问题标题】:RxJs Observable: Execute function if empty/filteredRxJs Observable:如果为空/过滤则执行函数
【发布时间】:2016-06-27 15:22:42
【问题描述】:

我有一个 Observable 可以监听来自文本框的一些用户输入。如果观察到的字符串长度 >=3 (filter),它将执行一些 HTTP 调用 (switchMap)。

现在我想以某种方式检测用户输入是否已被过滤。原因:

  • 如果 HTTP 调用已经完成,它应该会显示结果。

  • 如果用户输入被过滤(== 无效),它应该清除结果。

这是我想要的代码(请参阅:ifFiltered):

this.userInput.valueChanges
    .filter(val => val && val.length >= 3)
    .ifFiltered(() => this.results = [])
    .switchMap(val => getDataViaHTTP())
    .subscribe(val => this.results = val);

我知道,对于这个简单的示例,我可以将该逻辑放在 filter 函数中。但是如果我有 10 个不同的过滤器呢?

我是否错过了任何满足我需求的方法?

提前致谢!

【问题讨论】:

    标签: filter angular rxjs observable rxjs5


    【解决方案1】:

    我建议有一个共同的事件流,创建两个过滤流,并在订阅前合并两者:

    var o = this.userInput.valueChanges;
    
    var empty= o.filter(t=> t.length < 3)
    .map(t=>[])
    
    var nonempty = o.filter(t=> t.length >= 3)
        .switchMap(t=> getDataViaHTTP());
    
    empty.merge(nonempty).subscribe(val => this.results = val);
    

    【讨论】:

    • 看起来很不错,但是如果有 5 个过滤器,你会怎么做呢?我不想用正面和负面的方式来写每个过滤器。
    • 您可以保存合并的过滤器,并以多种方式将其与其他流结合起来。正/负过滤器只是在开始。
    【解决方案2】:

    要么使用这里的分区RxJS modeling if else control structures with Observables operators

    或者,如果前一个过滤条件为真,则使用映射和管道对象代替过滤器,否则为空。这样您就可以使用过滤器在链中的任意位置捕获 null。

    最后一个选项调用过滤函数else部分中的某个函数

    【讨论】:

    • 看起来有点老套,但使用o.map(val =&gt; (val &amp;&amp; val.length &gt;= 3)?val:null).subscribe(val =&gt; this.results = val==null ? [] : val)还是很不错的@
    • 什么是“过滤函数的else部分”?
    【解决方案3】:

    我使用Validators我的用例找到了另一个不错的解决方案:

    (我知道这不是问题所述使用 Observables 的解决方案。相反,它使用 Angular2 功能很好地解决了这个问题。)

    this.userInput.validator = Validators.compose([
        Validators.required,
        Validators.minLength(3)
    ]);
    
    this.userInput.valueChanges
        .filter(val => this.userInput.valid)
        .switchMap(val => getDataViaHTTP())
        .subscribe(val => this.results = val);
    

    现在我可以使用userInput.valid 属性和/或userInput.statusChanges Observable 来跟踪输入值。

    【讨论】:

      【解决方案4】:

      我们有一个类似的案例,并尝试使用上面提到的partition,但发现在这里使用throw 更方便。所以对于你的代码

      this.userInput.valueChanges
          .do(val => {
            if (!val || val.length < 3) {
              throw new ValueTooShortError();
            }
          })
          .switchMap(val => getDataViaHTTP())
          .do(val => this.results = val)
          .catch(() => this.results = [])
          .subscribe();
      

      【讨论】:

        【解决方案5】:

        可能已经晚了,但想为仍在寻求更清洁方法来验证 .map 中的 IF EMPTY 的成员发帖:

        of(fooBar).pipe(
              map(
                (val) =>
                  ({
                    ...val,
                    Foo: (val.Bar
                      ? val.Foo.map((e) => ({
                          title: e.Title,
                          link: e.Link,
                        }))
                      : []) as fooModal[],
                  }));
        

        如果缺少 val.bar,此代码将返回一个空数组,但这只是一个示例,您可以改用任何验证和表达式。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-04
          • 2023-04-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多