Как я могу отфильтровать Observable onKeyUp?

Как найти / отфильтровать наблюдаемый массив строк типа?

Например, у меня есть следующие наблюдаемые

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

Теперь я хотел бы отфильтровать это наблюдаемое в зависимости от того, какие типы пользователей вводятся в текстовое поле ввода.

Итак, у меня есть следующий код, и я хотел бы вернуть отфильтрованное наблюдаемое на основе searchTerm пользователя, введенного в поле ввода.

Обратите внимание, что я ищу решение на стороне клиента. У меня уже есть данные на стороне клиента, и по какой-то причине я не могу отправить поисковый запрос на сервер для фильтрации данных. Я также понимаю, что в этом примере я могу напрямую использовать фильтр для самого массива, но я хочу сделать это с помощью наблюдаемого.

Я также пробовал сглаживать массив с помощью оператора плоской карты, но все еще не смог вернуть наблюдаемое в конце, которое должно иметь тип строкового массива.

Любая помощь будет оценена. Заранее спасибо.

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'));
    }
}

person hp8888    schedule 12.12.2017    source источник
comment
Это мелочь, но вы слушаете событие нажатия клавиши и вызываете функцию keyup. Я не уверен, что у вас здесь такое поведение, как вы хотите.   -  person Brendan Whiting    schedule 12.12.2017
comment
@Brendan Whiting Спасибо за указание на ошибку. Я починил это.   -  person hp8888    schedule 12.12.2017


Ответы (2)


Вы делаете здесь несколько ошибок.

  1. Почему вы хотите сопоставить наблюдаемое с names.indexOf(value) > 0? .map() буквально преобразует наблюдаемое, и вы только что преобразовали наблюдаемое типа string в тип boolean.

  2. Если вы хотите, чтобы список names изменялся при нажатии пользователем (onkeyup), почему вы хотите снова переназначить this.names$ обратно на this.names$? Это заставит ваш код работать только после первого нажатия клавиши. У вас должны быть две переменные, одна для хранения значений, а другая для привязки к вашему ngModel.

  3. Если вы хотите использовать канал async, вам не нужно подписывать наблюдаемое в вашем файле машинописного текста.

В вашем 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);
        })
}

Рабочие Stackblitz: https://stackblitz.com/edit/angular-yeaer6

person CozyAzure    schedule 12.12.2017
comment
Спасибо за вашу помощь. Я понял все комментарии, которые вы упомянули, обновил код и исправил событие нажатия клавиши. Вот ссылка на stackblitz, которая выполняет именно то, что вы здесь упомянули. stackblitz.com/edit/angular-wtarys Однако я ожидаю увидеть обновленный отфильтрованный список, когда я изменяю текст, но он этого не делает. Есть идеи, почему? - person hp8888; 12.12.2017
comment
@ hp8888 мой плохой. Обновил код и опубликовал stackblitz. - person CozyAzure; 12.12.2017
comment
,,,, К сожалению, это все еще не работает или я не хочу. Я перешел на stackblitz. com / edit / angular-yeaer6 - ссылка, по которой должен быть рабочий код. Но когда я набираю «Del» в текстовом поле, он должен показать мне Dell в отфильтрованном списке, а это не так. Прошу прощения, но я должен указать на это. Аналогичным образом, если я наберу «Len», он должен отобразить Lenovo в отфильтрованном списке. Возможно, вы забыли сохранить изменения перед отправкой этой ссылки? - person hp8888; 12.12.2017
comment
@ hp8888 моя ошибка! Чтобы получить желаемое поведение, просто убедитесь, что мы сравниваем строчные буквы всех входов и списка. Ссылка обновлена. - person CozyAzure; 13.12.2017
comment
Большое спасибо, что нашли время ответить на мой вопрос .. Это именно то, что я хотел. Мне следовало разобраться в этом вопросе, чувствительном к регистру, самостоятельно. - person hp8888; 14.12.2017

попробуй это

let value='Del'
 Rx.Observable.from(['Lenovo','Dell','Toshiba','Apple','Microsoft'])
 .filter(name=>name.indexOf(value)!==-1)
 .subscribe(console.log);
person Fan Cheung    schedule 12.12.2017
comment
Привет, Фан Чунг, Спасибо, что уделили время, чтобы ответить на мой вопрос. Я попробовал код, который у вас есть, и он отлично работает. Однако у меня есть один вопрос. В тот момент, когда я меняю строку Observable.from на Observable.of, она перестает работать. Не могли бы вы объяснить, почему следующее не работает (обратите внимание, что я вызвал метод вместо from)? let value="Del" Rx.Observable.of(["Lenovo","Dell","Toshiba","Apple","Microsoft"]) .filter(name=>name.indexOf(value)!==-1) .subscribe(console.log); - person hp8888; 12.12.2017
comment
.of отправит вам весь список массивов в одной подписке, попробуйте .of (array) .subscribe (console.log) и from (array) .subscribe (console.log) и посмотрите разницу - person Fan Cheung; 13.12.2017