【问题标题】:How can I filter an Observable onKeyUp?如何过滤 Observable onKeyUp?
【发布时间】:2018-05-25 17:01:53
【问题描述】:

如何搜索/过滤字符串数组类型的可观察对象?

例如,我有以下 observable

names$ = Observable.of(['Lenovo','Dell','Toshiba','Apple','Microsoft']);

现在我想根据用户在输入文本框中输入的内容来过滤这个 observable。

所以我有以下代码,我想根据用户在输入框中输入的 searchTerm 返回过滤后的 observable。

请注意,我正在寻找客户端解决方案。我的数据已经在客户端,由于某种原因,我无法在服务器上发送搜索词来过滤数据。我也明白在这个例子中我可以直接在数组本身上使用过滤器,但我想通过 observable 来做到这一点。

我也尝试过 flatmap 运算符来展平数组,但最终仍然无法返回应为字符串数组类型的 observable。

任何帮助将不胜感激。提前致谢。

App.component.html

<!-- Textbox to receive user input -->
Search:<input type='text' [(ngModel)]='searchTerm' (keypress)='onkeypress($event.target.value)'>
<p>Search Term: {{searchTerm}}</p>
<hr>

<!-- Show search results here as ordered list -->
<ng-container *ngIf='(names$|async)?.length>0'>
    <ol>
        <li *ngFor='let name of names$|async'>
            {{name}}
        </li>
    </ol>
</ng-container>

App.component.ts

import {Component, OnInit} from '@angular/core';
import {Observable} from 'rxjs';

@Component({
    selector: 'my-app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
    names$: Observable<string[]>;
    filteredNames$: Observable<string[]>;
    searchTerm: string;

    ngOnInit() {
        this.names$ = Observable.of(['Lenovo', 'Dell', 'Toshiba', 'Apple', 'Microsoft']);
    }

    // HOW TO IMPLEMENT THIS FUNCTION ??
    onkeypress(value) {
        console.log(value);
        this.names$ = this.names$.map(names => names.indexOf(value) > 0)
        // .filter(x=>{console.log(x.indexOf(value));return x.indexOf(value)>0})
        //     .subscribe(
        // (data)=>console.log(data),      (error)=>console.log('Error'+error),
        //       ()=>console.log('complete'));
    }
}

【问题讨论】:

  • 这是一件小事,但您正在监听按键事件并调用函数 keyup。我不确定你是否有你想要的行为。
  • @Brendan Whiting 感谢您指出错误。我修好了。

标签: angular rxjs observable rxjs5 flatmap


【解决方案1】:

试试这个

let value='Del'
 Rx.Observable.from(['Lenovo','Dell','Toshiba','Apple','Microsoft'])
 .filter(name=>name.indexOf(value)!==-1)
 .subscribe(console.log);

【讨论】:

  • 您好 Fan Cheung,感谢您抽出时间回答我的问题。我试过你在这里的代码,它工作得很好。不过我有一个问题。当我将 Observable.from 更改为 Observable.of 时,它就停止了工作。你能解释一下为什么以下不起作用(注意我调用的是方法而不是方法)?let value="Del"Rx.Observable.of(["Lenovo","Dell","Toshiba","Apple","Microsoft"]).filter(name=&gt;name.indexOf(value)!==-1).subscribe(console.log);
  • .of 将在一个订阅中向您发送整个数组列表,尝试 .of(array).subscribe(console.log) 和 from(array).subscribe(console.log) 并查看区别
【解决方案2】:

您在这里犯了一些错误。

  1. 为什么要将 observable 映射到 names.indexOf(value) &gt; 0.map() 从字面上转换 observable,而您刚刚将 string 类型的 observable 转换为 boolean 类型。

  2. 如果您希望names 列表在用户键入(onkeyup)时更改,为什么要将this.names$ 重新分配回this.names$?这将使您的代码工作一次,也就是只在第一次击键上工作。您应该有两个变量,一个用于保存值,另一个用于绑定到您的 ngModel

  3. 如果您想使用async 管道,则无需在您的 typescript 文件中订阅 observable。

在您的 ngOnInit() 中,创建一个变量来跟踪您的姓名:

ngOnInit() {
    this.data$ = Observable.of(['Lenovo', 'Dell', 'Toshiba', 'Apple', 'Microsoft']);
    this.names$ = this.data$;
}

假设您使用的是async 管道,这应该是您的onKeyUp 函数:

onKeyUp(value) {
    this.names$ = this.data$
        .map(x => {
             return x.filter(y=>y.toLowerCase().indexOf(value.toLowerCase())>-1);
        })
}

正在工作的 Stackblits:https://stackblitz.com/edit/angular-yeaer6

【讨论】:

  • 感谢您的帮助。我了解您提到的所有 cmets 并更新了代码并修复了按键事件。这是 stackblitz 链接,它完全符合您在此处提到的内容。stackblitz.com/edit/angular-wtarys 但是,当我更改文本时,我希望看到过滤列表得到更新,但它没有这样做。知道为什么吗?
  • @hp8888 我的错。更新了代码,并发布了stackblitz。
  • ,,,,不幸的是,它仍然无法正常工作,或者这不是我想要的行为。我去了stackblitz.com/edit/angular-yeaer6,这是应该有工作代码的链接。但是,当我在文本框中键入“Del”时,它应该在过滤列表中显示 Dell,但它不是。我很抱歉,但我必须指出这一点。同样,如果我输入“Len”,它应该会在过滤列表中显示联想。您可能在发送此链接之前忘记保存更改?
  • @hp8888 我的错!要获得您想要的行为,只需确保我们比较所有输入和列表的小写。链接已更新。
  • 非常感谢您花时间回答我的问题。这正是我想要的。我应该自己弄清楚区分大小写的问题。
猜你喜欢
  • 1970-01-01
  • 2015-08-27
  • 2018-06-27
  • 1970-01-01
  • 1970-01-01
  • 2020-09-03
  • 2019-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多