RxJs Observable:如果为空/过滤则执行函数

Posted

技术标签:

【中文标题】RxJs Observable:如果为空/过滤则执行函数【英文标题】:RxJs Observable: Execute function if empty/filtered 【发布时间】: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 个不同的过滤器呢?

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

提前致谢!

【问题讨论】:

【参考方案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,此代码将返回一个空数组,但这只是一个示例,您可以改用任何验证和表达式。

【讨论】:

以上是关于RxJs Observable:如果为空/过滤则执行函数的主要内容,如果未能解决你的问题,请参考以下文章

Rxjs 过滤器运算符不适用于 Angular2 Observable

RxJS之过滤操作符 ( Angular环境 )

我可以使用 rxjs 针对 id 的字符串数组过滤 Observable

RXJS Observable 数组上的简单过滤器

RxJS if-else 类似管道过滤

RxJS过滤数据流操作符学习 (Filtering Operators)