- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试实现一个异步验证器但没有成功......
我的组件创建了一个表单:
this.personForm = this._frmBldr.group({
lastname: [ '', Validators.compose([Validators.required, Validators.minLength(2) ]) ],
firstname: [ '', Validators.compose([Validators.required, Validators.minLength(2) ]) ],
birthdate: [ '', Validators.compose([ Validators.required, DateValidators.checkIsNotInTheFuture ]) ],
driverLicenceDate: [ '', Validators.compose([ Validators.required, DateValidators.checkIsNotInTheFuture ]), this.asyncValidationLicenceDate.bind(this) ],
}, {
asyncValidator: this.validateBusiness.bind(this),
validator: this.validateDriverLicenseOlderThanBirthdate,
});
validateBusiness(group: FormGroup) {
console.log('validateBusiness')
return this._frmService
.validateForm(group.value)
.map((validationResponse: IValidationResponse) => {
if (validationResponse) {
validationResponse.validations.forEach( (validationError: IValidationErrorDescription) => {
let errorMsg = validationError.display;
let errorCode = validationError.code;
validationError.fields.forEach( (fieldName: string) => {
console.log(fieldName);
let control = this.personForm.controls[fieldName];
let existingErrors = control.errors || {};
existingErrors[errorCode] = errorMsg;
control.setErrors(existingErrors);
});
});
}
});
}
extra.asyncValidator
的
formbuilder.group
参数中)从未被调用过......有人能告诉我我做错了什么吗?
最佳答案
TL;博士:通过分析您的用例,您可能需要 解决方案 2
问题
问题在于如何定义和使用异步验证器。
异步验证器定义为:
export interface AsyncValidatorFn {
(c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null>;
}
FormBuilder.group()
实际上是在调用
FormGroup
构造函数:
constructor(controls: {
[key: string]: AbstractControl;
}, validator?: ValidatorFn | null, asyncValidator?: AsyncValidatorFn | null);
AbstractControl
实例,在这种情况下,是
FormGroup
例如,因为验证器位于
FormGroup
等级。验证器需要返回
Promise
或
Observable
的
ValidationErrors
,如果不存在验证错误,则为 null。
ValidationErrors
被定义为字符串键和值的映射(任何你喜欢的)。键实际上是定义验证错误类型的字符串(例如:“required”)。
export declare type ValidationErrors = {
[key: string]: any;
};
AbstractControl.setErrors()?
- 在您的示例中,您正在定义一个不返回任何内容但实际上直接更改控制错误的函数。调用
setErrors
仅适用于手动调用验证并因此只能手动设置错误的情况。相反,在您的示例中,这些方法是混合的,
FormControl
s 附加了将自动运行的验证功能,以及
FormGroup
异步验证功能也自动运行,尝试手动设置错误并因此设置有效性。这是行不通的。
AbstractControl
实例。 FormControl
验证将只处理一个控件。
FormGroup
验证会将表单组的多个方面视为一个整体。
FormGroup
上有一个验证器使用您的验证服务的级别,那么这可以使用
来实现解决方案 1 .
<form [formGroup]="personForm">
<div>
<input type="text" name="firstName" formControlName="firstName" placeholder="First Name" />
</div>
<div>
<input type="text" name="lastName" formControlName="lastName" placeholder="Last Name" />
</div>
<p style="color: red" *ngIf="personForm.errors?.sameValue">First name and last name should not be the same.</p>
<button type="submit">Submit</button>
</form>
validateBusiness
验证函数将返回
Promise
:
import { Component, OnInit } from '@angular/core';
import {AbstractControl, FormBuilder, FormGroup, ValidationErrors, Validators} from "@angular/forms";
import {Observable} from "rxjs/Observable";
import "rxjs/add/operator/delay";
import "rxjs/add/operator/map";
import "rxjs/add/observable/from";
@Component({
selector: 'app-async-validation',
templateUrl: './async-validation.component.html',
styleUrls: ['./async-validation.component.css']
})
export class AsyncValidationComponent implements OnInit {
personForm: FormGroup;
constructor(private _formBuilder: FormBuilder) { }
ngOnInit() {
this.personForm = this._formBuilder.group({
firstName: [ '', Validators.required ],
lastName: [ '', Validators.required ],
}, {
asyncValidator: this.validateBusiness.bind(this)
});
}
validateBusiness(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (control.value.firstName !== control.value.lastName) {
resolve(null);
}
else {
resolve({sameValue: 'ERROR...'});
}
},
1000);
});
}
}
Observable
:
validateBusiness(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
return Observable
.from([control.value.firstName !== control.value.lastName])
.map(valid => valid ? null : {sameValue: 'ERROR...'})
.delay(1000);
}
FormGroup
使用。和
FormControl
异步验证器。
import {IValidationErrorDescription} from "./IValidationErrorDescription";
export interface IValidationResponse {
validations: IValidationErrorDescription[];
}
export interface IValidationErrorDescription {
display: string;
code: string;
fields: string[];
}
import { Injectable } from '@angular/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/from';
import 'rxjs/add/operator/map';
import {IValidationResponse} from "../model/IValidationResponse";
@Injectable()
export class BusinessValidationService {
public validateForm(value: any): Observable<IValidationResponse> {
return Observable
.from([value.firstName !== value.lastName])
.map(valid => valid ?
{validations: []}
:
{
validations: [
{
code: 'sameValue',
display: 'First name and last name are the same',
fields: ['firstName', 'lastName']
}
]
}
)
.delay(500);
}
}
FormGroup
构建异步验证器的验证服务和
FormControl
并订阅表单数据的更改,以便将验证委托(delegate)给验证回调(例如:
BusinessValidationService
)。
validateFormOnChange()
- 当表单更改时,它会调用验证回调 validateFormCallback
以及何时触发 FormGroup
的验证和 FormControl
s 使用 control.validateFormGroup()
. createGroupAsyncValidator()
- 为 FormGroup
创建一个异步验证器createControlAsyncValidator()
- 为 FormControl
创建一个异步验证器import { Injectable } from '@angular/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/from';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/first';
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/debounceTime';
import {AbstractControl, AsyncValidatorFn, FormGroup} from '@angular/forms';
import {ReplaySubject} from 'rxjs/ReplaySubject';
import {IValidationResponse} from "../model/IValidationResponse";
@Injectable()
export class FormValidationService {
private _subject$ = new ReplaySubject<IValidationResponse>(1);
private _validationResponse$ = this._subject$.debounceTime(100).share();
private _oldValue = null;
constructor() {
this._subject$.subscribe();
}
public get onValidate(): Observable<IValidationResponse> {
return this._subject$.map(response => response);
}
public validateFormOnChange(group: FormGroup, validateFormCallback: (value: any) => Observable<IValidationResponse>) {
group.valueChanges.subscribe(value => {
const isChanged = this.isChanged(value, this._oldValue);
this._oldValue = value;
if (!isChanged) {
return;
}
this._subject$.next({validations: []});
this.validateFormGroup(group);
validateFormCallback(value).subscribe(validationRes => {
this._subject$.next(validationRes);
this.validateFormGroup(group);
});
});
}
private isChanged(newValue, oldValue): boolean {
if (!newValue) {
return true;
}
return !!Object.keys(newValue).find(key => !oldValue || newValue[key] !== oldValue[key]);
}
private validateFormGroup(group: FormGroup) {
group.updateValueAndValidity({ emitEvent: true, onlySelf: false });
Object.keys(group.controls).forEach(controlName => {
group.controls[controlName].updateValueAndValidity({ emitEvent: true, onlySelf: false });
});
}
public createControlAsyncValidator(fieldName: string): AsyncValidatorFn {
return (control: AbstractControl) => {
return this._validationResponse$
.switchMap(validationRes => {
const errors = validationRes.validations
.filter(validation => validation.fields.indexOf(fieldName) >= 0)
.reduce((errorMap, validation) => {
errorMap[validation.code] = validation.display;
return errorMap;
}, {});
return Observable.from([errors]);
})
.first();
};
}
public createGroupAsyncValidator(): AsyncValidatorFn {
return (control: AbstractControl) => {
return this._validationResponse$
.switchMap(validationRes => {
const errors = validationRes.validations
.reduce((errorMap, validation) => {
errorMap[validation.code] = validation.display;
return errorMap;
}, {});
return Observable.from([errors]);
})
.first();
};
}
}
firstName
和
lastName
FormControl
s 位于
personForm
内
FormGroup
.对于此示例,条件是
firstName
和
lastName
应该不同。
<form [formGroup]="personForm">
<div>
<label for="firstName">First name:</label>
<input type="text"
id="firstName"
name="firstName"
formControlName="firstName"
placeholder="First Name" />
<span *ngIf="personForm.controls['firstName'].errors?.sameValue">Same as last name</span>
</div>
<div>
<label for="lastName">Last name:</label>
<input type="text"
id="lastName"
name="lastName"
formControlName="lastName"
placeholder="Last Name" />
<span *ngIf="personForm.controls['lastName'].errors?.sameValue">Same as first name</span>
</div>
<p style="color: red" *ngIf="personForm.errors?.sameValue">First name and last name should not be the same.</p>
<button type="submit">Submit</button>
</form>
FrmValidationService
实现验证.由于
providers: [FormValidationService]
,此组件有自己的此服务实例.由于 Angular 分层注入(inject)器功能,一个注入(inject)器将与此组件相关联,并且将为
AsyncValidateFormComponent
的每个实例创建此服务的一个实例。 .因此能够在每个组件实例的基础上跟踪此服务内部的验证状态。
import { Component, OnInit } from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/from';
import {FormValidationService} from "../services/form-validation.service";
import {BusinessValidationService} from "../services/business-validation.service";
@Component({
selector: 'app-async-validate-form',
templateUrl: './async-validate-form.component.html',
styleUrls: ['./async-validate-form.component.css'],
providers: [FormValidationService]
})
export class AsyncValidateFormComponent implements OnInit {
personForm: FormGroup;
constructor(private _formBuilder: FormBuilder,
private _formValidationService: FormValidationService,
private _businessValidationService: BusinessValidationService) {
}
ngOnInit() {
this.personForm = this._formBuilder.group({
firstName: ['', Validators.required, this._formValidationService.createControlAsyncValidator('firstName')],
lastName: ['', Validators.required, this._formValidationService.createControlAsyncValidator('lastName')],
}, {
asyncValidator: this._formValidationService.createGroupAsyncValidator()
});
this._formValidationService.validateFormOnChange(this.personForm, value => this._businessValidationService.validateForm(value));
}
}
ReactiveFormsModule
为了与
FormBuilder
一起工作,
FormGroup
和
FormControl
.还提供了
BusinessValidationService
.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { AsyncValidateFormComponent } from './async-validate-form/async-validate-form.component';
import {BusinessValidationService} from "./services/business-validation.service";
@NgModule({
declarations: [
AppComponent,
AsyncValidateFormComponent
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
HttpModule
],
providers: [
BusinessValidationService
],
bootstrap: [AppComponent]
})
export class AppModule { }
关于angular2 formBuilder 组异步验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44134892/
我有类似的问题: How do I resolve the error I am encountering using custom Validator syntax? FormBuilder gro
我有一个 CRUD 网络表,用于添加、编辑、删除......我使用 FormBuilder 进行表单验证。 this.saisieForm = this.fb.group({ 'val1':
我想知道是否有一种方法可以使用 Angular 2 的 FormBuilder 设置嵌套属性,如下所示: this.form = formBuilder.group({ name: ['', Va
我有这个实现 FormBuilder 的表单。 我需要在输入字段下显示我的自定义验证消息。使用下面的代码,验证器可以在输入字段为空白但不显示我的自定义验证时显示红色的“错误”文本。 .html 和 .
我正在尝试实现一个异步验证器但没有成功...... 我的组件创建了一个表单: this.personForm = this._frmBldr.group({ lastname: [ '', Va
我试图使用 Angular FormBuilder 提供的额外参数映射 group(controlsConfig: { [key: string]: any; }, extra: {
我将我的项目迁移到 angular 11,我注意到我添加的全局验证使 FormBuilder.group不推荐使用以下消息: group is deprecated: This api is not
根据 the Reactive Forms documentation ,我可以从 重构我的 FormGroup 定义 this.heroForm = this.fb.group({ name:
我通过扩展选择字段 (following the tutorial in the cookbook) 创建了自定义“状态”表单类型。选择字段的选项是根据通过服务注入(inject)的参数自动填充的。但
Angular 2,4 formbuilder setvalue() 在下拉选择中使用时无法按预期工作。 我有以下由 Github 组织填充的下拉选择: {{org.organizati
如何在选择的多个上正确构建 FormBuilder? 它只有在没有多重的情况下才有效。 我尝试在 HTML 中使用 FormArray、FormGroupName,但是,都返回错误。而且我遇到的例子总
我正在使用以下 jQuery Formbuilder ( http://formbuilder.readthedocs.io/en/latest/formBuilder/options/typeUse
我使用 Formbuilder 创建一个 FormGroup: myForm = this.fb.group( { title: [""],
我在 Angular 4 中使用 FormBuilder,当没有填写所有字段时,我需要禁用提交按钮。 component.ts public loginForm = this.fb.group({ e
根据 API 文档,更改嵌套值的正确方法是使用方法 patchValue myForm.patchValue({'key': {'subKey': 'newValue'}}); 但如何更改嵌套数组中的
当您有非常定制化的需求时,将 formbuild 与 pylons 结合使用实际上比手动创建您自己的表单 html 更容易吗? 最佳答案 我真的更喜欢纯 html,但它 super 简单使用如下语法填
Angular doc here您可以看到下面的实现。即在 constructor() 中声明 formBuilder 和服务。我知道在 constructor() 中使用服务是一种不好的做法。即我们
我有简单的 Angular FormBuilder 表单(在 Ionic 2 应用程序中),包含 3 个字段: constructor(public navCtrl: NavController, p
我使用 Wagtail 贡献的表单构建器模块在 Wagtail Admin 中创建了一个简单的联系人表单。该表单具有动态添加的字段Name、Email、Subject和Message;模型 Conta
我在一些选择选项中有一个硬空间 ( )。不知何故,在某个地方,他们正在逃脱。我试过: {% autoescape false %} {{ form_widget(foobar) }} {% e
我是一名优秀的程序员,十分优秀!