Использование RXJS для входных данных поиска, которые выполняют вызов API, но подписка происходит многократно, даже с debounceTime - PullRequest
1 голос
/ 20 сентября 2019

У меня есть поле ввода поиска в html, которое подключено к ViewChild в моем файле компонента.

<input #userSearch type="text" placeholder="Search by Name or Email...">
@ViewChild('userSearch', {static: false}) set userSearch(input: ElementRef|null) {
        if (!input) return;
        this.setInput(input);
    }

public setInput(input) {
        fromEvent(input.nativeElement, 'keyup')
            .pipe(
                auditTime(1000),
                map((event:any) => {
                    return event.target.value;
                }),
                debounceTime(1000),
                distinctUntilChanged(),
            )
            .subscribe((text: string) => {
                this.count++
                console.log("count ++ is", this.count)
                this.searchTerm = text;
                console.log("this.searchTerm", this.searchTerm)
                if (this.searchTerm.length > 2) {
                    this._loadUsers({
                        search_name_or_email: this.searchTerm
                    });
                } else {
                    this._loadUsers();
                }
            });

    }

В моей функции setInput я использую debounceTime и auditTime с намерением, что когдапользователь заканчивает ввод, этот поисковый термин будет затем отправлен для вызова API.

Проблема в том, что, когда я набираю поисковый запрос "Ron", мой console.log возвращает count ++, равный единице.Когда я удаляю свой поисковый термин, подписка запускается несколько раз, поэтому теперь мой счетчик приближается к 8. Когда я набираю новый поисковый термин, счетчик срабатывает как 15 каждый раз, когда я удаляю и добавляю новый поисковый термин., блок подписки запускается повторно, что означает, что вызов api в this._loadUsers вызывается повторно, что является проблемой.

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

ОБНОВЛЕНИЕ: Спасибо, что взглянули на это.Я удалил audTime, и это все еще вызывает проблемы.Я отладил проблему для этого метода установки в конструкторе.Я не знаком с этим методом установки ViewChild, но из некоторой документации я нашел https://blog.angularindepth.com/beware-angular-can-steal-your-time-41fe589483df (точка # 2), его необходимо использовать, когда элемент ref ref вложен в * ngIf.По какой-то причине этот метод setter срабатывает несколько раз при редактировании поискового запроса, и я не уверен, почему из-за моего недостаточного знакомства с методами setter для ViewChild.


export class UsersComponent implements OnInit {
    @ViewChild('userSearch', {static: false}) set userSearch(input: ElementRef|null) {
        if (!input) return;
        this.count++
        console.log("count ++ is", this.count)
        this.setInput(input);
    }

Ответы [ 2 ]

0 голосов
/ 21 сентября 2019

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

<input type="text" placeholder="Search by Name or Email..." (keyup)="search($event.target.value)">

и в TypeScript

search$ = new Subject();

search(val) {
  this.search$.next(val);
}

ngOnInit() {
    this.search$
        .pipe(
            auditTime(1000),
            map((event:any) => {
                return event.target.value;
            }),
            debounceTime(1000),
            distinctUntilChanged(),
        )
        .subscribe((text: string) => {
            this.count++
            console.log("count ++ is", this.count)
            this.searchTerm = text;
            console.log("this.searchTerm", this.searchTerm)
            if (this.searchTerm.length > 2) {
                this._loadUsers({
                    search_name_or_email: this.searchTerm
                });
            } else {
                this._loadUsers();
            }
        });
 }
0 голосов
/ 20 сентября 2019

Избавление от AuditTime, похоже, решает проблему

const { fromEvent } = rxjs;
const { auditTime, map, debounceTime, distinctUntilChanged } = rxjs.operators;

fromEvent(document.getElementById('userSearch'), 'keyup')
    .pipe(
        //auditTime(1000),
        map(event => {
            return event.target.value;
        }),
        debounceTime(1000),
        distinctUntilChanged()
    )
    .subscribe(text => {
        console.log("Text is: ", text);
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"></script>
<input id="userSearch" type="text" placeholder="Search by Name or Email...">
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...