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>
标签时自动应用的 另一个 指令。
- 令人困惑的注释:
NgForm
和 FormGroupDirective
在它们的源代码中都有 exportAs: 'ngForm'
,(它们也都声明了 submitted
和 ngSubmit
属性) .但是当我输入 #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
- 而 FormGroup
有 touched
、pristine
、dirty
.
之类的东西
此示例适用于 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,请尝试使用旧的 ?
。
我有一个看起来像这样的简单表格
<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>
标签时自动应用的 另一个 指令。 - 令人困惑的注释:
NgForm
和FormGroupDirective
在它们的源代码中都有exportAs: 'ngForm'
,(它们也都声明了submitted
和ngSubmit
属性) .但是当我输入#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
- 而 FormGroup
有 touched
、pristine
、dirty
.
此示例适用于 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,请尝试使用旧的 ?
。