移动目标元素时未触发单击处理程序

时间:2017-12-28 16:43:19

标签: angular angular-reactive-forms

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

我有反应式表单控件,同步验证程序和错误消息显示在字段下面时无效。

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

我已使用评论更新了演示。注意:输入下方的仅按钮将重现该问题。第一次点击后,标题不会更新。

4 个答案:

答案 0 :(得分:4)

问题在GitHub的issue #7113中讨论过。这是因为在点击按钮有机会完成并触发click事件之前,当输入字段失去焦点时执行验证。

可能的解决方法是使用标记在点击按钮时隐藏消息,如this stackblitz所示。在下面的代码中,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来改进该解决方案。它将说明用户在未完成点击的情况下离开按钮的情况。

答案 1 :(得分:1)

该问题似乎与触发订单的DOM事件有关

根据MDN:

  

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

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

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

因此鼠标在按钮上方时关闭,但向上时 - 按钮会重新定位。因此,按钮上不会触发click

有几种方法可以解决这个问题:

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

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

希望这会有所帮助:)

答案 2 :(得分:0)

好吧,我想我会跟着。您不希望在单击下方按钮时进行验证。

触发验证的原因是由于表单输入上的autofocus。 Angular“默认情况下,只要值发生变化,控件的值和有效性就会更新。” See FormControl。该控件正在将name.untouchedfalse更改为true

如果您向模板添加一些额外的调试绑定,您可以观察到这种情况。 e.g。

<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>

如果要在用户单击下方按钮时隐藏错误消息,则应在调用autofocus时删除onClick2()或重置表单验证。或者,您只能在表单出错时显示错误消息。 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>

答案 3 :(得分:0)

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

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

现在,对于您的提交按钮,您不想取消blur事件,但是您可能希望在mousedown上运行某种验证逻辑。这样考虑一下,如果按钮已移动,则表示表单中存在错误。表格有误时该怎么办?就我而言,我真正想做的就是将所有控件标记为已触摸,以便显示所有验证错误。

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