Angular2 - 从外部验证和提交表单

Angular2 - Validate and submit form from outside

我有一个看起来像这样的简单表格

<form (ngSubmit)="save()" #documentEditForm="ngForm">
...
</form>

并且需要提交表格并从外部

检查其有效性

例如。要么以编程方式提交,要么使用 <form> 标签之外的 <button type="submit">

了解如何操作:

  • 触发提交 <formname>.ngSubmit.emit()
  • 使用 <formname>.form.valid
  • 获取表单状态

示例:

<form (ngSubmit)="save()" #documentEditForm="ngForm">
...
</form>

<button class="btn-save button primary"
(click)="documentEditForm.ngSubmit.emit()"
[disabled]="!documentEditForm.form.valid">SAVE</button>

编辑:正如@yuriy-yakovenko 指出的那样,您应该在组件代码中添加以下内容:

@ViewChild('documentEditForm') documentEditForm: FormGroupDirective; 

如果您还没有导入 FormGroupDirective,请不要忘记导入

您可以 link 使用按钮上的表单属性将按钮添加到表单:

<form (ngSubmit)="save()" id="ngForm" #documentEditForm="ngForm"> 
  ... 
</form>

<button form="ngForm">
  SAVE
</button>

您仍然可以像这样检查其有效性:

<button form="ngForm" [disabled]="!documentEditForm.form.valid">
  SAVE
</button>

表单需要有一个 ID id="example-form",提交按钮需要一个匹配的 ID form="example-form"

详情请看这里:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-form

一个对我有用的技巧

  • 反应形式
  • 角度2
  • 包括。浏览器

是这样的:

<!-- real button will simulate click on invisible button (cf. form) -->
<button onclick="document.getElementById('hiddenSaveButtonForMicrosoftWithLove').click()">
  The Real Button outside forms
</button>

<form>
  <!-- will be called in the background and is never visible -->
  <button id="hiddenSaveButtonForMicrosoftWithLove" type="submit" style="display: none;">hiddenSaveButtonForMicrosoftWithLove</button>
</form>

如果您使用的是响应式表单,请使用无效的表单组 属性 禁用提交按钮:

<button  
  form="ngForm"
  [disabled]=" editor.invalid>Enviar</button> 

...

<form [formGroup]="editor"  id="ngForm"   (ngSubmit)="save()" novalidate >
...
</form>

以下解决方案适用于我的情况,请尝试这个简单的解决方案。我不确定它是否适用于所有条件:

<form #documentEditForm="ngForm" id="ngForm" (ngSubmit)="save(documentEditForm.valid)"> 
    ...Your Input Elements... 
</form>

按钮应该像这样在表单外声明:

<button form="ngForm">Submit</button>

表单验证应按以下条件save()检查

save(isValid:boolean){
    if(isValid) {
        ...Your code to save details...
    }
}

希望这个简单的解决方案对您有所帮助。

重要:如果使用 Angular material 表单控件 + 响应式表单

调用 onSubmit(undefined)[formGroup] 指令上正确设置 submitted = true

注意:指令与angular形式本身不是同一个对象(更多内容见下文)

这是 sourcecode for the [formGroup] directive 的一部分。 (对于反应形式)

@Directive({
  selector: '[formGroup]',
  providers: [formDirectiveProvider],
  host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'},
  exportAs: 'ngForm'
})
export class FormGroupDirective extends ControlContainer implements Form,
    OnChanges {
  /**
   * @description
   * Reports whether the form submission has been triggered.
   */
  public readonly submitted: boolean = false;

 .....

 onSubmit($event: Event): boolean {
    (this as{submitted: boolean}).submitted = true;
    syncPendingControls(this.form, this.directives);
    this.ngSubmit.emit($event);
    return false;
 }

你这样使用它:

<form [formGroup]="form" #formRef="ngForm">

并且您可以通过以下方式在 ts 文件中获取对 FormGroupDirective 的引用:

@ViewChild('formRef') 
formRef: FormGroupDirective;
  • 注意:NgForm 是在您创建 <form> 标签时自动应用的 另一个 指令。
  • 令人困惑的注释:NgFormFormGroupDirective 在它们的源代码中都有 exportAs: 'ngForm',(它们也都声明了 submittedngSubmit 属性) .但是当我输入 #ngForm='ngForm' 时,我得到一个类型为 FormGroupDirective 而不是 NgForm 的对象(在调试器中验证)。我不确定为什么 - 但这就是为什么我将其声明为 FormGroupDirective 而不是 NgForm - 我想也许是第一个获胜。

你这样使用它:

this.formRef.onSubmit(undefined)

示例:

// html
<form [formGroup]="form" #formRef="ngForm">
    // ...Form Controls
</form>

// component.ts
export class MyComponent {

    @ViewChild('formRef')
    formRef: FormGroupDirective;

    form: FormGroup = new FormGroup({
        myInput: new FormControl(''),
        //etc...
    });

    submitFormProgrammatically() {
        this.formRef.onSubmit(undefined);
    }
}

如果您只是像其他一些答案所建议的那样调用 this.formRef.ngSubmit.emit(),您将无法获得所有重要的 submitted = true 集。

为什么这很重要?

如果您使用任何 Angular CDK 或 Angular Material 控件,则不会显示错误情况,除非表单域已被触摸(单击或获得焦点)或整个表单已提交。

因此,如果您缺少必填字段 ,即 mouse/cursor 从未输入过 ,那么即使您输入 [=35],该字段也不会显示为红色=](因为 submitted = false 对于窗体和控件有 touched = false)。

那么它如何使用常规提交按钮正常工作?

通常如果你有<button type='submit'>Submit</button>(在<form>标签内)它会触发标准HTML <form>提交(与[=125=无关) ]) - 这会在表单标签上引发标准 submit 事件。

如果 <form> 标签上也有一个 [formGroup] 指令(如上所示),那么 HTML 表单 submit 事件是 'caught'指令,这就是导致调用上面的 onSubmit() 函数的原因。

这又会引发 ngSubmit 事件 - 如果您需要进行进一步处理,您可以自行捕获该事件 - 例如显示警报。

因此,在使用 material(反应式表单)控件时调用 onSubmit 而不是 ngSubmit.emit 以使验证处理正常工作非常重要。 $event 参数只能为 null 或未定义。

进一步阅读:查看ErrorStateMatcher(仅适用于Angular CDK/Material)以了解确切的规则。如果解决默认设置的限制变得过于复杂,您可以创建自己的。

更令人困惑: [formGroup] 指令与仅保存数据的 FormGroup 不是同一个对象。只有指令上有 submitted - 而 FormGrouptouchedpristinedirty.

之类的东西

此示例适用于 Angular 6 及更高版本

<form (ngSubmit)="save()" id="ngForm" [formGroup]="form"> 
    ... 
</form>

<button type="submit" class="btn-save button primary" form="ngForm">Save</button>

这对我有用。

<form #editForm="ngForm">
  <button type="button" (click)="editForm.submitted = true; editForm.ngSubmit.emit(); anotherMethod();">
    Submit programatically
  </button>
</form>

关键是同时设置 submitted = true 和发出 ngSubmit 事件。

我写这个答案是希望它能帮助到一些人。我花了一整天的时间试图解决这个问题,跟踪其中的每一个答案和评论......但我仍然收到错误消息,指出找不到#documentEditForm(我的等价物)(无法读取 属性 x of undefined ...),无论我尝试过什么。

我认为 'outside' 表单标签有问题的原因是,当我将 submit/validation 按钮放在 </form> 中时,这个问题就消失了标签。我进入了这个兔子洞,但后来意识到我需要脱离形式是有正当理由的。

但后来我意识到我必须做两件事来解决这个问题:(1) 在验证时将 ? 添加到 ngForm 的名称中,以及 (2) 实现 ViewChild(NgForm) documentEditForm!: NgForm.

<form #documentEditForm="ngForm">
...
</form>

<button class="btn-save button primary" (click)="save()" [disabled]="documentEditForm?.invalid">
   SAVE
</button>

里面 component.ts:

import { Component, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';

export class XYZComponent implements OnInit {

  @ViewChild(NgForm) documentEditForm!: NgForm;

...

在 Angular 中使用模板驱动的表单并使用 #form_name="ngForm" 语法时,您将它暴露在表单内部。但是,当您使用 ViewChild 时,您会将表单公开给整个组件,而不仅仅是在表单内部。请记住,如果应用程序无法编译或出现意外 output/error,请尝试使用旧的 ?