移动目标元素后,不会触发单击处理程序



请考虑以下演示 https://stackblitz.com/edit/angular-pur1dt

我有带有同步验证器的反应式表单控件,当它失效时,字段下方会显示错误消息。

当控件失去焦点时,将触发验证。控件下方有一个具有单击处理程序的按钮。问题是,当我单击按钮时,控件失去焦点,发生验证,显示错误消息并向下移动按钮。据说这会阻止单击处理程序执行。任何建议为什么会发生这种情况以及如何解决问题?

我已经用评论更新了演示。注意:只有输入下方的按钮才会重现问题。首次单击标题后,标题不会更新。

这个问题在 GitHub 上的问题 #7113 中讨论过。这是由于以下事实引起的:在输入字段失去焦点之前,在单击按钮有机会完成并触发click事件之前,会执行验证。

一种可能的解决方法是在单击按钮正在进行时使用标志来隐藏消息,如本堆栈闪电战所示。在下面的代码中,isClicking标志是在mousedown事件上单击开始时设置的,并在click事件完成时重置。

<p #errorMsg [hidden]="(errorMsg.hidden && isClicking) || form.controls.name.valid || form.controls.name.untouched ">
Invalid :)
</p>
<button (mousedown)="onMouseDown($event)" (click)="onClick2($event)">click NOT ok</button>
export class AppComponent {
isClicking = false;
...
onMouseDown(event) {
this.isClicking = true;
setTimeout(() => {
// The click action began but was not completed after two seconds
this.isClicking = false;
}, 2000);
}
onClick2(event) {
console.log(event);
this.name = "NOT";
this.isClicking = false;
}
}

可以通过将setTimeout替换为在mousedown事件处理程序中捕获鼠标的过程,并在捕获丢失时重置isClicking来改进该解决方案。它将考虑用户在没有完成单击的情况下离开按钮的情况。

该问题似乎与触发顺序的 DOM 事件有关

根据MDN:

单击事件在指针设备按钮(通常为 鼠标的主按钮)在单个元素上按下并释放。

https://developer.mozilla.org/en-US/docs/Web/Events/click

在给定的示例中,元素在您blur输入的那一刻移动 - 因为验证会立即发生,显示错误并重新定位按钮。

因此,鼠标在按钮上方时处于关闭状态,但当鼠标向上,按钮会重新定位。所以click不会在按钮上触发

有几个选项可以解决此问题:

  • mousedown延迟错误显示
  • 隐藏错误,直到mousedownmouseup都发生(如果按钮上发生了mousedown)

下面是一个mousedown事件处理的示例 https://jsfiddle.net/gjbgqqpo/

希望这对:)有所帮助

好的,我想我遵循。您不希望在单击下按钮时进行验证。

触发验证的原因是因为表单输入上的autofocus。Angular "默认情况下,控件的值和有效性会在值更改时更新。" 请参阅表单控件。控件正在将name.untouchedfalse更改为true

如果向模板添加一些额外的调试绑定,则可以看到这种情况发生。 例如

<hello name="{{ name }}"></hello>
<form [formGroup]="form">
<input formControlName="name" autofocus>
<button (click)="onClick($event)">click OK</button>
</form>
<pre>{{form.controls.name.valid}}</pre>
<pre>{{form.controls.name.untouched}}</pre>
<p [hidden]="form.controls.name.valid || form.controls.name.untouched ">
Invalid :)
</p>
<button (click)="onClick2($event)">click NOT ok</button>

如果要在用户单击下方按钮时隐藏错误消息,则应在调用onClick2()时删除autofocus或重置窗体的验证。或者,您可以在表单出现错误时显示错误消息。Angular 说A control is untouched if the user has not yet triggered a blur event on it.单击下方按钮会导致模糊事件。

为什么不直接将错误消息上的模板绑定更改为

<p [hidden]="!form.controls.name.valid || form.controls.name.untouched">
Invalid :)
</p>

一个简单的解决方案是将(mousedown)="false"添加到关闭按钮。这样就不会发生模糊事件,因为鼠标按下处理程序将取消按钮上的焦点事件。反过来,这不会将控件标记为已触摸,并且不会显示您的错误。

<button type="button" (click)="dismiss()" (mousedown)="false">Cancel</button>

现在对于提交按钮,您不想取消模糊事件,但您可能希望在鼠标按下时运行某种验证逻辑。这样想一想,如果按钮移动了,这意味着表单中存在错误。当表单中出现错误时,您想做什么?就我而言,我真正想做的是将所有控件标记为已触摸,以便显示所有验证错误。

<button type="submit" (mousedown)="form.markAllAsTouched()">Create</button>

相关内容

  • 没有找到相关文章

最新更新