如何在对用户输入进行异步调用时过滤项目?

How to filter items while doing async calls on user input?

我的 HTML 中有一个输入字段,如下所示:

<input (keyup)="userInput($event)" type="text">

在我的组件中,我接受用户输入并检查后端是否是有效输入。在进行此调用之前,我对变量进行了简单的空检查。

userInput(e: any): void {
    this.userInputText = e.target.value;
    if (this.userInputText === '') { //Empty string check
        this.validInput = false;
    } else { // Check backend for availability
        this.userInput.next(this.userInputText);
    }
}

我的用户输入主题是

this.userInput
.debounceTime(1000)
.switchMap((val) => {
    return this.checkValidity(val); //service call
}).subscribe((res) => {
    this.validInput = res.status;
}, (err) => {
    ResponseHandler(err);
});

问题是我做的空头支票。

假设用户输入了两个字符 'of',我将其显示为有效(通过调用)。

如果用户按下退格键(输入现在是 'o'),等待一秒钟(导致调用文本 'o')然后按下退格键删除 'o'(导致空的用户输入)我的状态显示无效,因为输入字段为空。

然后 ajax 呼叫响应返回(对于文本 'o',这是有效的)并且我显示有效。所以我最终显示对空字符串有效。 我该如何解决这个问题?有什么想法吗?

问题是您正在执行异步操作并期望同步结果。您需要找到一种方法来解决程序的异步性质。

立即想到的一些可能的解决方案:

1) 您可以在进行服务器端验证时禁用输入。

2) 由于解决方案 1 不太流畅,您可以考虑在将请求发送到服务器之前设置一个标志(例如 input_changed_during request = false;,在输入更改时修改其值(例如 input_changed_during_request = true;,然后在收到来自服务器的状态后检查它,如果输入在验证过程中被修改,则丢弃您的验证结果。

3) 您可以在客户端执行去抖动输入验证,然后在提交时到达服务器时重新验证输入。

您只需要将空支票放入可观察流中,而无需进行其他工作...

this.userInput
 .debounceTime(1000)
 .distinctUntilChanged()
 .switchMap((val) => (val) ? this.checkValidity(val) : Observable.of({status: false}))
 .subscribe((res) => {
       this.validInput = res.status;
 }, (err) => {
    ResponseHandler(err);
 });

然后直接将密钥绑定到用户输入主题

由于 switchmap 运算符的工作方式,这解决了您的计时问题。

switchMap 获取一个值并将其映射到对新内部可观察对象的订阅,但更重要的是,它取消并忽略了之前订阅的内部可观察对象的值。这就是为什么对于 switch map,如果用户输入 w 然后 o,switch map 收到 "w" 然后 "wo" 并不重要,因为一旦它获得第二个值,异步 "w" 查询是否有 returned,或者如果 "wo" 查询(以某种方式)击败了 "w" 查询,因为它将忽略或取消 "w" 查询一旦它收到新的 "wo" 值,空白值也是如此,就好像用户在之前的查询完成之前删除了他们的输入一样,switchMap 将忽略或取消所有之前未完成的查询,并且它将仅 return 来自最新内部可观察对象的模拟无效查询结果。这就是它被称为 switchMap 的原因,它切换并映射到最新的内部可观察对象。

如果你要使用像 mergeMap 这样的运算符,它是一个不同的高阶运算符,它也映射到一个新的内部可观察对象,这个过程将不起作用,因为 mergeMap 不会切换,它 returns 所有来自内部可观察值的值按它们到达的顺序排列,不管新值进来什么。有时这就是你所追求的,但在这种情况下不是。

额外提示,我添加的 distinctUntilChanged() 运算符使此过程更加高效,就好像用户要执行类似输入 w(执行查询)然后输入 o 并立即删除debounce 时间帧,它将忽略下一个发送的 "w",因为它只将新值传递给 switchmap 并忽略顺序重复值,因此您不必重新查询 "w"