对 Angular 2 个响应式表单执行跨域验证
Performing cross-field validation on Angular 2 Reactive Forms
我正在尝试使用 Reactive Forms 模块在 Angular 2 中构建注册表单。因此,我为表单定义了一个 FormGroup,然后我可以在其中列出每个 FormControl 的验证器。
考虑这部分 class:
export class TestFormComponent implements OnInit {
form: FormGroup;
password = new FormControl("", [Validators.required]);
passwordConfirm = new FormControl("", [Validators.required, this.validatePasswordConfirmation]);
constructor(private fb: FormBuilder) {
}
ngOnInit() {
this.form = this.fb.group({
"password": this.password,
"passwordConfirm": this.passwordConfirm
});
}
validatePasswordConfirmation(fc: FormControl) {
var pw2 = fc.value;
var pw = // how do I get this value properly????
if (pw === '') {
return {err:"Password is blank"};
}
if (pw2 === '') {
return {err:"Confirmation password is blank"};
}
if (pw !== pw2) {
return {err:"Passwords do not match"}
}
return null;
}
}
你可以看到我为 passwordConfirm
字段创建了一个验证器,但我不知道如何获取主 password
字段的值(用作 pw
在验证器中)进行比较。
我不能只引用 this.form.value.password
,因为验证器中的 this
没有引用包含表单的主要 class。
有什么想法吗?
所以答案是在整个表单上放置一个新的验证器,然后使用传递给验证器的 FormGroup 对象作为比较字段值的方法。我怀疑的就这么多。但是,我缺少的是如何在单个 passwordConfirm
字段上正确设置错误状态。此代码显示了如何执行此操作:
export class TestFormComponent implements OnInit {
form: FormGroup;
password = new FormControl("", [Validators.required]);
passwordConfirm = new FormControl("", [Validators.required, this.validatePasswordConfirmation]);
constructor(private fb: FormBuilder) {
}
ngOnInit() {
this.form = this.fb.group({
"password": this.password,
"passwordConfirm": this.passwordConfirm
},
{
validator: this.validatePasswordConfirmation
});
}
validatePasswordConfirmation(group: FormGroup) {
var pw = group.controls['password'];
var pw2 = group.controls['passwordConfirm'];
if (pw.value !== pw2.value) { // this is the trick
pw2.setErrors({validatePasswordConfirmation: true});
}
// even though there was an error, we still return null
// since the new error state was set on the individual field
return null;
}
}
如上面代码的注释中所述,技巧是您可以使用 setErrors()
方法在单个 FormControl
字段上设置错误状态。所以现在,有了这段代码,确认字段根据它拥有的常规验证器(如 Validators.required
以及我们添加的基于自定义表单的验证器获得正确的 valid/invalid 状态集。
使用此方法,您可以创建复杂的基于表单的验证器,这些验证器可以检查许多不同表单字段的状态,并根据您能想到的任何业务逻辑分别设置每个表单字段的验证状态。这使得使用 Angular 2 响应式表单的跨域验证变得非常简单。
Michael Oryl 的回答对我来说有两个错误,也许我使用了不同的版本 (Angular 2.3.0):
1。
passwordConfirm = new FormControl("", [Validators.required, this.validatePasswordConfirmation]);
应该是:
passwordConfirm = new FormControl("", [Validators.required]);
因为比:
validatePasswordConfirmation(group: FormGroup)
触发 FormGroup 的子元素。我不知道为什么,但它发生了。所以整个组的第二个验证器就足够了,因为它会触发整个 FormGroup。
当在重复字段之后编辑原始字段并且两个字段相等时,Michaels 代码保持错误状态。
在这种情况下,这段代码在更复杂的验证中完成了工作,您需要更复杂的东西:
if (pw.value != pw2.value) {
pw2.setErrors({validatePasswordConfirmation: true});
}
else{
pw2.setErrors(null);
}
完整代码:
export class TestFormComponent implements OnInit {
form: FormGroup;
password = new FormControl("", [Validators.required]);
passwordConfirm = new FormControl("", [Validators.required]);
constructor(private fb: FormBuilder) {
}
ngOnInit() {
this.form = this.fb.group({
"password": this.password,
"passwordConfirm": this.passwordConfirm
},
{
validator: this.validatePasswordConfirmation
});
}
validatePasswordConfirmation(group: FormGroup) {
var pw = group.controls['password'];
var pw2 = group.controls['passwordConfirm'];
if (pw.value !== pw2.value) { // this is the trick
pw2.setErrors({validatePasswordConfirmation: true});
}else{
pw2.setErrors(null);
}
return null;
}
}
pw2.setErrors(null);
如果 pw2 字段本身有验证器,例如 minLength
:
会导致问题
ngOnInit() {
this.form = this.fb.group({
"password": [this.password, Validators.minLength(6)],
"passwordConfirm": [this.passwordConfirm, Validators.minLength(6)]
},
{
validator: this.validatePasswordConfirmation
});
}
setErrors(null)
将破坏 minLength 警告。
最好是跨域验证器 validatePasswordConfirmation()
returns 错误代替,因为 错误出现在 HTML - - 除了一个单独的字段,或 above/below 整个表单 - 无论如何都完全在我们的控制之下。
<div *ngIf="myNgForm.submitted" class="text-error">
<span *ngIf="form.errors?.validatePasswordConfirmation">This field must match the first field</span>
<span *ngIf="form.controls.passwordConfirm.errors?.minlength">must be at least 6 chars</span>
</div>
我正在尝试使用 Reactive Forms 模块在 Angular 2 中构建注册表单。因此,我为表单定义了一个 FormGroup,然后我可以在其中列出每个 FormControl 的验证器。
考虑这部分 class:
export class TestFormComponent implements OnInit {
form: FormGroup;
password = new FormControl("", [Validators.required]);
passwordConfirm = new FormControl("", [Validators.required, this.validatePasswordConfirmation]);
constructor(private fb: FormBuilder) {
}
ngOnInit() {
this.form = this.fb.group({
"password": this.password,
"passwordConfirm": this.passwordConfirm
});
}
validatePasswordConfirmation(fc: FormControl) {
var pw2 = fc.value;
var pw = // how do I get this value properly????
if (pw === '') {
return {err:"Password is blank"};
}
if (pw2 === '') {
return {err:"Confirmation password is blank"};
}
if (pw !== pw2) {
return {err:"Passwords do not match"}
}
return null;
}
}
你可以看到我为 passwordConfirm
字段创建了一个验证器,但我不知道如何获取主 password
字段的值(用作 pw
在验证器中)进行比较。
我不能只引用 this.form.value.password
,因为验证器中的 this
没有引用包含表单的主要 class。
有什么想法吗?
所以答案是在整个表单上放置一个新的验证器,然后使用传递给验证器的 FormGroup 对象作为比较字段值的方法。我怀疑的就这么多。但是,我缺少的是如何在单个 passwordConfirm
字段上正确设置错误状态。此代码显示了如何执行此操作:
export class TestFormComponent implements OnInit {
form: FormGroup;
password = new FormControl("", [Validators.required]);
passwordConfirm = new FormControl("", [Validators.required, this.validatePasswordConfirmation]);
constructor(private fb: FormBuilder) {
}
ngOnInit() {
this.form = this.fb.group({
"password": this.password,
"passwordConfirm": this.passwordConfirm
},
{
validator: this.validatePasswordConfirmation
});
}
validatePasswordConfirmation(group: FormGroup) {
var pw = group.controls['password'];
var pw2 = group.controls['passwordConfirm'];
if (pw.value !== pw2.value) { // this is the trick
pw2.setErrors({validatePasswordConfirmation: true});
}
// even though there was an error, we still return null
// since the new error state was set on the individual field
return null;
}
}
如上面代码的注释中所述,技巧是您可以使用 setErrors()
方法在单个 FormControl
字段上设置错误状态。所以现在,有了这段代码,确认字段根据它拥有的常规验证器(如 Validators.required
以及我们添加的基于自定义表单的验证器获得正确的 valid/invalid 状态集。
使用此方法,您可以创建复杂的基于表单的验证器,这些验证器可以检查许多不同表单字段的状态,并根据您能想到的任何业务逻辑分别设置每个表单字段的验证状态。这使得使用 Angular 2 响应式表单的跨域验证变得非常简单。
Michael Oryl 的回答对我来说有两个错误,也许我使用了不同的版本 (Angular 2.3.0):
1。 passwordConfirm = new FormControl("", [Validators.required, this.validatePasswordConfirmation]);
应该是:
passwordConfirm = new FormControl("", [Validators.required]);
因为比:
validatePasswordConfirmation(group: FormGroup)
触发 FormGroup 的子元素。我不知道为什么,但它发生了。所以整个组的第二个验证器就足够了,因为它会触发整个 FormGroup。
当在重复字段之后编辑原始字段并且两个字段相等时,Michaels 代码保持错误状态。 在这种情况下,这段代码在更复杂的验证中完成了工作,您需要更复杂的东西:
if (pw.value != pw2.value) { pw2.setErrors({validatePasswordConfirmation: true}); } else{ pw2.setErrors(null); }
完整代码:
export class TestFormComponent implements OnInit {
form: FormGroup;
password = new FormControl("", [Validators.required]);
passwordConfirm = new FormControl("", [Validators.required]);
constructor(private fb: FormBuilder) {
}
ngOnInit() {
this.form = this.fb.group({
"password": this.password,
"passwordConfirm": this.passwordConfirm
},
{
validator: this.validatePasswordConfirmation
});
}
validatePasswordConfirmation(group: FormGroup) {
var pw = group.controls['password'];
var pw2 = group.controls['passwordConfirm'];
if (pw.value !== pw2.value) { // this is the trick
pw2.setErrors({validatePasswordConfirmation: true});
}else{
pw2.setErrors(null);
}
return null;
}
}
pw2.setErrors(null);
如果 pw2 字段本身有验证器,例如 minLength
:
ngOnInit() {
this.form = this.fb.group({
"password": [this.password, Validators.minLength(6)],
"passwordConfirm": [this.passwordConfirm, Validators.minLength(6)]
},
{
validator: this.validatePasswordConfirmation
});
}
setErrors(null)
将破坏 minLength 警告。
最好是跨域验证器 validatePasswordConfirmation()
returns 错误代替,因为 错误出现在 HTML - - 除了一个单独的字段,或 above/below 整个表单 - 无论如何都完全在我们的控制之下。
<div *ngIf="myNgForm.submitted" class="text-error">
<span *ngIf="form.errors?.validatePasswordConfirmation">This field must match the first field</span>
<span *ngIf="form.controls.passwordConfirm.errors?.minlength">must be at least 6 chars</span>
</div>