我试图添加不会使表单无效的表单验证。验证应仅显示为警告。
E.g。年龄验证。年龄大于90表示警告,年龄大于120表示错误。
我已尝试在表单上使用两个FormGroup,在输入字段上使用两个[formControl]。只使用了第一个[formControl]。
是否可以使用Angulars表单验证进行此类验证?哪种方法可行?
答案 0 :(得分:16)
我是通过创建自定义验证程序来完成的,它始终返回null
。此验证器还会创建其他属性warnings
。然后只需从您的视图中查看此属性即可。
export interface AbstractControlWarn extends AbstractControl { warnings: any; }
export function tooBigAgeWarning(c: AbstractControlWarn) {
if (!c.value) { return null; }
let val = +c.value;
c.warnings = val > 90 && val <= 120 ? { tooBigAge: {val} } : null;
return null;
}
export function impossibleAgeValidator(c: AbstractControl) {
if (tooBigAgeWarning(c) !== null) { return null; }
let val = +c.value;
return val > 120 ? { impossibleAge: {val} } : null;
}
@Component({
selector: 'my-app',
template: `
<div [formGroup]="form">
Age: <input formControlName="age"/>
<div *ngIf="age.errors?.required" [hidden]="age.pristine">
Error! Age is required
</div>
<div *ngIf="age.errors?.impossibleAge" [hidden]="age.pristine">
Error! Age is greater then 120
</div>
<div *ngIf="age.warnings?.tooBigAge" [hidden]="age.pristine">
Warning! Age is greater then 90
</div>
<p><button type=button [disabled]="!form.valid">Send</button>
</div>
`,
})
export class App {
age: FormControl;
constructor(private _fb: FormBuilder) { }
ngOnInit() {
this.form = this._fb.group({
age: ['', [
Validators.required,
tooBigAgeWarning,
impossibleAgeValidator]]
})
this.age = this.form.get("age");
}
}
答案 1 :(得分:1)
确定
通过angular.io可以很容易地进行表单验证,暗示你可以阅读https://angular.io/docs/ts/latest/cookbook/form-validation.html上的文件
但可以在我的脑海中找到可以帮助你更好的类似方式。
首先我们创建一个名为Form的抽象类,它包含一些常用的函数和属性。
import {FormGroup} from "@angular/forms";
export abstract class Form {
form: FormGroup;
protected abstract formErrors: Object;
protected abstract validationMessages: Object;
onValueChanged(data?: any) {
if (!this.form) { return; }
const form = this.form;
for (const field in this.formErrors) {
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] = messages[key];
break;
}
}
}
}
}
然后你应该创建一个表单组件,例如名为LoginComponent,如下面的
import {Component, OnInit} from "@angular/core";
import {Form} from "./form";
import {Validators, FormBuilder} from "@angular/forms";
@Component({
templateUrl: '...'
})
export class LoginComponent extends Form implements OnInit {
protected formErrors = {
'email': '',
'password': ''
}
protected validationMessages = {
'email': {
'required': 'email required message',
'email': 'email validation message'
},
'password': {
'required': 'password required message',
'minlength': 'password min length message',
'maxlength': 'password max length message',
}
}
constructor(private _fb: FormBuilder) { }
ngOnInit() {
this.buildForm();
}
buildForm() {
this.form = this._fb.group({
'email': ['', [
Validators.required,
// emailValidator
]],
'password': ['', [
Validators.required,
Validators.minLength(8),
Validators.maxLength(30)
]]
});
this.form.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged(); //
}
}
首先我们应该为反应形式注入FormBuilder(不要忘记在主模块中导入ReactiveFormModule)然后在[buildForm()]方法中我们在表单属性上构建一组表单,该表单继承自抽象类Form。 / p>
然后在接下来我们创建表单值更改的订阅,并且在值更改时我们调用[onValueChanged()]方法。
在[onValueChanged()]方法中我们检查表单的字段是否有效,如果不是,我们从protected validationMessages属性中获取消息并在formErrors属性中显示它。
那么你的模板应该与此类似
<div class="col-md-4 col-md-offset-4">
<form [formGroup]="form" novalidate>
<div class="form-group">
<label class="control-label" for="email">email</label>
<input type="email" formControlName="email" id="email" class="form-control" required>
<div class="help help-block" *ngIf="formErrors.email">
<p>{{ formErrors.email }}</p>
</div>
</div>
<div class="form-group">
<label class="control-label" for="password">password</label>
<input type="password" formControlName="password" id="password" class="form-control" required>
<div class="help help-block" *ngIf="formErrors.password">
<p>{{ formErrors.password }}</p>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-block btn-primary" [disabled]="!form.valid">login</button>
</div>
</form>
</div>
模板非常简单,内部检查字段是否有错误,如果有错误绑定。
对于bootstrap,您可以执行下面的其他操作
<div class="form-group" [ngClass]="{'has-error': form.controls['email'].dirty && !form.controls['email'].valid, 'has-success': form.controls['email'].valid}">
<label class="control-label" for="email">email</label>
<input type="email"
formControlName="email"
id="email"
class="form-control"
required>
<div class="help help-block" *ngIf="formErrors.email">
<p>{{ formErrors.email }}</p>
</div>
</div>
更新:我尝试为您创建一个非常简单但几乎完整的示例,您当然可以开发更狂野的规模: https://embed.plnkr.co/ExRUOtSrJV9VQfsRfkkJ/
但有一点描述,你可以创建如下的自定义验证
import {ValidatorFn, AbstractControl} from '@angular/forms';
function isEmptyInputValue(value: any) {
return value == null || typeof value === 'string' && value.length === 0;
}
export class MQValidators {
static age(max: number, validatorName: string = 'age'): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
if (isEmptyInputValue(control.value)) return null;
const value = typeof control.value == 'number' ? control.value : parseInt(control.value);
if (isNaN(value)) return null;
if (value <= max) return null;
let result = {};
result[validatorName] = {valid: false};
return result;
}
}
}
这个自定义验证器得到一个名为validatorName的可选参数,这个参数会导致您指定多个类似的验证,如示例中的formComponent应如下所示:
buildForm () {
this.form = this._fb.group({
'age': ['', [
Validators.required,
Validators.pattern('[0-9]*'),
MQValidators.age(90, 'abnormalAge'),
MQValidators.age(120, 'incredibleAge')
]]
});
this.form.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged();
}
onValueChanged(data?: any): void {
if (!this.form) { return; }
const form = this.form;
for (const field in this.formErrors) {
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] = messages[key];
}
}
}
}
formErrors = {
age: ''
}
validationMessages = {
'age': {
'required': 'age is required.',
'pattern': 'age should be integer.',
'abnormalAge': 'age higher than 90 is abnormal !!!',
'incredibleAge': 'age higher than 120 is incredible !!!'
}
}
希望我帮助过。
答案 2 :(得分:1)
Sergey Voronezhskiy可接受的答案在开发模式下是完美的,但是如果您尝试在--prod模式下进行构建,则会出现此错误。
... Property 'warnings' does not exist on type 'FormControl'.
为了解决此错误,我对原始代码进行了调整,基本上是为了修复松散类型的变量,这是新版本:
export class FormControlWarn extends FormControl { warnings: any; }
export function tooBigAgeWarning(c: FormControlWarn ) {
if (!c.value) { return null; }
let val = +c.value;
c.warnings = val > 90 && val <= 120 ? { tooBigAge: {val} } : null;
return null;
}
export function impossibleAgeValidator(c: AbstractControl) {
if (tooBigAgeWarning(c) !== null) { return null; }
let val = +c.value;
return val > 120 ? { impossibleAge: {val} } : null;
}
@Component({
selector: 'my-app',
template: `
<div [formGroup]="form">
Age: <input formControlName="age"/>
<div *ngIf="age.errors?.required" [hidden]="age.pristine">
Error! Age is required
</div>
<div *ngIf="age.errors?.impossibleAge" [hidden]="age.pristine">
Error! Age is greater then 120
</div>
<div *ngIf="age.warnings?.tooBigAge" [hidden]="age.pristine">
Warning! Age is greater then 90
</div>
<p><button type=button [disabled]="!form.valid">Send</button>
</div>
`,
})
export class App {
get age(): FormControlWarn{
return <FormControlWarn>this.form.get("age");
}
constructor(private _fb: FormBuilder) { }
ngOnInit() {
this.form = this._fb.group({
age: new FormControlWarn('', [
Validators.required,
tooBigAgeWarning,
impossibleAgeValidator])
});
}
}
答案 3 :(得分:0)
这可能就是我的做法。
<form #form="ngForm" (ngSubmit)="save()">
<input formControlName="controlName">
<span *ngIf="form.pristine && form.controls.controlName.value > 90 && form.controls.controlName.value < 120">
Warning: Age limit is high..
</span>
<span *ngIf="form.pristine && form.controls.controlName.value > 120">
Error: Age limit exceeded..
</span>
<form>