Angular|RxJS - Type-ahead 搜索请求被浏览器取消(点击)
Angular|RxJS - Type-ahead search request gets cancelled by browser (on click)
我是 RxJS(和前端)的新手,但我知道以下代码中的 switchMap()
用于在用户输入文本框时中断和重新 运行 搜索请求.搜索工作正常,唯一的问题是如果用户在输入文本和在请求完成之前,浏览器完全取消了搜索请求。
(注:如果用户在处理请求的过程中不断输入,则搜索请求被取消并重新运行正确。只有点击事件会导致完全取消请求,而不会重新运行)
search = (input: Observable<string>) => {
return input.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap((text) => text.length < 2 ? this.clearDropDown() // clear dropdown showing list of item names.
: this.onKeyUp(text).pipe(
map(result => {
this.spinnerService.end(); // stop loading spinner.
if (results.data) {
return results.data; // return list of item names for the dropdown.
}
})
)));
}
onKeyUp(text: string): Observable<any> {
this.spinnerService.start(); // start loading spinner animation overlay on the page.
return this.http.post(this.apiUrlString, { 'itemName': text }); // this search request works fine.
}
HTML,万一是相关的:
<div>
<input
id="itemSearchValue"
type="text"
class="form-control/bg-light/rounded/dropdown-toggle"
[(ngModel)]="selectedItem"
(selectItem)="onSelectItem($event)" // irrelevant to the question.
formControlName="itemSearchValue"
[ngbTypeahead]="search"
#instance="ngbTypeahead" />
</div>
当用户在某处发出点击时,如何确保请求不会被浏览器取消?我想保留 switchMap()
方法。
似乎所有订阅都被取消了onBlur
来自github:https://github.com/ng-bootstrap/ng-bootstrap/blob/master/src/typeahead/typeahead.ts
handleBlur() {
this._resubscribeTypeahead.next(null);
this._onTouched();
}
所以解决方案是不让 type-ahead 访问网络请求订阅。只需在组件内订阅并传递对数据的引用即可。
data: string[] = [];
sub = new Subscription();
search = (input: Observable<string>) => {
return input.pipe(
debounceTime(500), // half second buffer before request starts
distinctUntilChanged(),
switchMap((text) => {
if (text.length < 2) {
this.clearDropDown(); // clear dropdown showing list of item names.
return [];
}
this.subscribeToKeyUp(text); // update data
return [this.data];
})
);
};
subscribeToKeyUp(text: string) {
this.sub.unsubscribe(); // cancel if a request is still going
this.spinnerService.start(); // start loading spinner animation overlay on the page.
this.sub = this.onKeyUp(text).subscribe((results) => {
if (results?.data) this.data = results.data;
this.spinnerService.end(); // stop loading spinner.
});
}
onKeyUp(text: string): Observable<any> {
return this.http.post(this.apiUrlString, { itemName: text });
}
这是一个模拟请求和响应之间 3 秒延迟的 stackblitz。在半秒去抖时间和 3 秒响应之间单击关闭仍然允许请求完成。
https://stackblitz.com/edit/angular-cgyadh?file=src/app/typeahead-basic.ts
P.S. 我看到你提到请求可能需要 30 多秒,在那种情况下我会制作一个按钮来调用 subscribeToKeyUp(text)
和从 search
函数中删除该调用。这样就不会在每封信上都触发大量请求。无论如何只是一个建议。
我是 RxJS(和前端)的新手,但我知道以下代码中的 switchMap()
用于在用户输入文本框时中断和重新 运行 搜索请求.搜索工作正常,唯一的问题是如果用户在输入文本和在请求完成之前,浏览器完全取消了搜索请求。
(注:如果用户在处理请求的过程中不断输入,则搜索请求被取消并重新运行正确。只有点击事件会导致完全取消请求,而不会重新运行)
search = (input: Observable<string>) => {
return input.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap((text) => text.length < 2 ? this.clearDropDown() // clear dropdown showing list of item names.
: this.onKeyUp(text).pipe(
map(result => {
this.spinnerService.end(); // stop loading spinner.
if (results.data) {
return results.data; // return list of item names for the dropdown.
}
})
)));
}
onKeyUp(text: string): Observable<any> {
this.spinnerService.start(); // start loading spinner animation overlay on the page.
return this.http.post(this.apiUrlString, { 'itemName': text }); // this search request works fine.
}
HTML,万一是相关的:
<div>
<input
id="itemSearchValue"
type="text"
class="form-control/bg-light/rounded/dropdown-toggle"
[(ngModel)]="selectedItem"
(selectItem)="onSelectItem($event)" // irrelevant to the question.
formControlName="itemSearchValue"
[ngbTypeahead]="search"
#instance="ngbTypeahead" />
</div>
当用户在某处发出点击时,如何确保请求不会被浏览器取消?我想保留 switchMap()
方法。
似乎所有订阅都被取消了onBlur
来自github:https://github.com/ng-bootstrap/ng-bootstrap/blob/master/src/typeahead/typeahead.ts
handleBlur() {
this._resubscribeTypeahead.next(null);
this._onTouched();
}
所以解决方案是不让 type-ahead 访问网络请求订阅。只需在组件内订阅并传递对数据的引用即可。
data: string[] = [];
sub = new Subscription();
search = (input: Observable<string>) => {
return input.pipe(
debounceTime(500), // half second buffer before request starts
distinctUntilChanged(),
switchMap((text) => {
if (text.length < 2) {
this.clearDropDown(); // clear dropdown showing list of item names.
return [];
}
this.subscribeToKeyUp(text); // update data
return [this.data];
})
);
};
subscribeToKeyUp(text: string) {
this.sub.unsubscribe(); // cancel if a request is still going
this.spinnerService.start(); // start loading spinner animation overlay on the page.
this.sub = this.onKeyUp(text).subscribe((results) => {
if (results?.data) this.data = results.data;
this.spinnerService.end(); // stop loading spinner.
});
}
onKeyUp(text: string): Observable<any> {
return this.http.post(this.apiUrlString, { itemName: text });
}
这是一个模拟请求和响应之间 3 秒延迟的 stackblitz。在半秒去抖时间和 3 秒响应之间单击关闭仍然允许请求完成。
https://stackblitz.com/edit/angular-cgyadh?file=src/app/typeahead-basic.ts
P.S. 我看到你提到请求可能需要 30 多秒,在那种情况下我会制作一个按钮来调用 subscribeToKeyUp(text)
和从 search
函数中删除该调用。这样就不会在每封信上都触发大量请求。无论如何只是一个建议。