表单验证 (Angular)
Form Validation (Angular)
我正在使用 angular 反应形式并制作距离输入字段,它有两个输入框,分别称为 From
和 To
。
HTML:
<form [formGroup]="form">
<button (click)="addRow()">Add</button>
<div formArrayName="distance">
<div
*ngFor="let item of form.get('distance').controls; let i = index"
[formGroupName]="i"
style="display: flex"
>
<input type="number" placeholder="From" formControlName="from" />
<div><input type="number" placeholder="To" formControlName="to" /></div>
</div>
</div>
<br /><br />
<button type="submit" [disabled]="!form.valid">Submit</button>
</form>
TypeScript:
ngOnInit() {
this.form = this.fb.group({
distance: this.fb.array([]),
});
this.addRow()
}
addRow() {
const control = this.form.controls.distance as FormArray;
control.push(this.fb.group({
from: ['',Validators.required],
to: ['',Validators.required]
}));
}
这里可以看到默认的两个输入框from
和to
.
顶部有一个添加按钮,单击添加按钮后,将添加具有相同输入字段的行并形成数组。
这里我需要限制用户不应该进入前一行到值,也不是值小于那个。
例如,
在第一行中,如果用户输入以下值,例如 0 和 5 分别代表 from 和 to,
"distance": [
{
"from": 0,
"to": 5
}
]
单击添加后,在 From 输入框的第二行中,需要限制用户添加小于等于 5 的值(这意味着这些值已经输入) .
这样是无效的,
{
"distance": [
{
"from": 0,
"to": 5
},
{
"from": 5,
"to": 10
}
]
}
此处"from": 5,
或"from": 4(or)3(or)2(or)1
,第二行中的任何内容均无效..
只有 6 和大于 6 才有效。
同样,对于每一行,它都需要检查前一行的值,并且需要进行验证。
请帮助我实现这种限制用户输入前一行的值(或)小于当前行的起始值的验证类型。
工作示例: https://stackblitz.com/edit/disable-group-control-value-on-another-control-value-for-j58atx
编辑:
尝试输入更改,例如
<input type="number" (input)="onInputChange($event.target.value)" placeholder="From" formControlName="from">
在 link https://stackblitz.com/edit/disable-group-control-value-on-another-control-value-for-ymfpkj 但不确定我是否正确..
此程序如有错误请修改
只需要使用一个customValidation(我在同一个组件中选择验证
ngOnInit() {
this.form = this.fb.group({
distance: this.fb.array([], this.distanceValidator()),
});
this.addRow()
}
distanceValidator() {
return (fa: FormArray) => {
let ok = true;
let ok2 = fa.value.length ? (!fa.value[0].to || !fa.value[0].from) || fa.value[0].to > fa.value[0].from : true;
if (!ok2)
return { error: "from greater than to" }
for (let i = 1; i < fa.value.length; i++) {
if (fa.value[i].from && fa.value[i].to )
{
ok = (fa.value[i].from > fa.value[i - 1].to || fa.value[i].to < fa.value[i - 1].from);
ok2 = (fa.value[i].to > fa.value[i].from);
if (!ok)
return { error: "from/to yet included" }
if (!ok2)
return { error: "from greater than to" }
}
}
return ok && ok2 ? null : !ok?{ error: "from yet included" }:{ error: "from greater than to" }
}
}
您可以像另一个人一样看到错误
<div *ngIf="form.get('distance')?.errors">
{{form.get('distance')?.errors.error}}
</div>
参见 [stackblitz 分叉][1]
最后我决定把这两个条件分开。见 new stackblitz
ngOnInit() {
this.form = this.fb.group({
distance: this.fb.array([], this.distanceValidator()),
});
this.addRow()
}
addRow() {
const control = this.form.controls.distance as FormArray;
control.push(this.fb.group({
from: ['', Validators.required],
to: ['', Validators.required]
}, { validator: this.greaterValidator() }));
}
setDefault() {
const control = this.form.controls.distance as FormArray;
this.default.forEach(data => {
control.push(this.fb.group({
from: [data.from, Validators.required],
to: [data.to, Validators.required]
}, { validator: this.greaterValidator() }));
});
}
greaterValidator() {
return (fa: FormGroup) => {
return fa.value.to && fa.value.to < fa.value.from ? { error: "from greater than to" } : null;
}
}
distanceValidator() {
return (fa: FormArray) => {
let ok = true;
for (let i = 1; i < fa.value.length; i++) {
ok = (!fa.value[i].from || fa.value[i].from > fa.value[i - 1].to) && (!fa.value[i].to || fa.value[i].to > fa.value[i - 1].from);
if (!ok)
return { error: "from/to yet included", index: i }
}
return null
}
}
还有.html
<form [formGroup]="form">
<button (click)="addRow()">Add</button>
<div formArrayName="distance" >
<div
*ngFor="let item of form.get('distance').controls; let i = index"
[formGroupName]="i"
style="display: flex">
<input type="number"
placeholder="From"
formControlName="from">
<div>
<input type="number"
placeholder="To"
formControlName="to">
</div>
<span *ngIf="item.errors">*</span>
<span *ngIf="form.get('distance')?.errors && form.get('distance')?.errors.index==i">**</span>
</div>
</div>
<div *ngIf="form.get('distance')?.errors">{{form.get('distance')?.errors.error}}</div>
<br><br>
<button type="submit" [disabled]="!form.valid"> Submit </button>
</form>
<button (click)="setDefault()"> Set Default Values </button>
更新:其实只有在发现错误的时候才控制更多。
此外,如果 from 和 to before 为空,则不要报错。为了避免这种情况,我们可以 "convert" 编号,写作
let ok = (!fa.value[i].from || fa.value[i].from > +fa.value[i - 1].to)
&& (!fa.value[i].to || fa.value[i].to > +fa.value[i - 1].from);
(参见+fa.value[i-1].to 和+fa.value[i-1].from
中的“+”
好吧,当我们决定我们发送的错误时,假设您有 6 行,位置 0、位置 3 和位置 4 的行(0 是第一行)发送一个错误,如
{error:"there are errors",indexError:",0,3,4,"}
这允许在*ngFor里面写一些像
<span *ngIf="form.get('distance')?.errors &&
form.get('distance')?.errors.indexError.indexOf(','+i+',')>=0">
**
</span>
嗯,我们的 distanceValidator 变成了这样
distanceValidator() {
return (fa: FormArray) => {
let indexError:string="";
for (let i = 1; i < fa.value.length; i++) {
let ok = (!fa.value[i].from || fa.value[i].from > +fa.value[i - 1].to) && (!fa.value[i].to || fa.value[i].to > +fa.value[i - 1].from);
if (!ok)
indexError+=','+i;
}
return indexError?{error:"there are errors",indexError:indexError+','}:null
}
有人会认为 return 错误数组更好,但这不允许以简单的方式知道有错误的行。有些像 errors.find(x=>x.id==i) 不起作用,因为我们不能在插值中使用查找。
确实只比较了一行和之前的中间行。可以在使用 for (let j=i-1;j>0;j++){ok=ok && ...}- 之前检查所有内容,但我认为这不是必需的,我们必须在代码中吝啬。请记住,函数 distanceValidator 被执行了几次
再看一个stackblitz
我正在使用 angular 反应形式并制作距离输入字段,它有两个输入框,分别称为 From
和 To
。
HTML:
<form [formGroup]="form">
<button (click)="addRow()">Add</button>
<div formArrayName="distance">
<div
*ngFor="let item of form.get('distance').controls; let i = index"
[formGroupName]="i"
style="display: flex"
>
<input type="number" placeholder="From" formControlName="from" />
<div><input type="number" placeholder="To" formControlName="to" /></div>
</div>
</div>
<br /><br />
<button type="submit" [disabled]="!form.valid">Submit</button>
</form>
TypeScript:
ngOnInit() {
this.form = this.fb.group({
distance: this.fb.array([]),
});
this.addRow()
}
addRow() {
const control = this.form.controls.distance as FormArray;
control.push(this.fb.group({
from: ['',Validators.required],
to: ['',Validators.required]
}));
}
这里可以看到默认的两个输入框from
和to
.
顶部有一个添加按钮,单击添加按钮后,将添加具有相同输入字段的行并形成数组。
这里我需要限制用户不应该进入前一行到值,也不是值小于那个。
例如,
在第一行中,如果用户输入以下值,例如 0 和 5 分别代表 from 和 to,
"distance": [
{
"from": 0,
"to": 5
}
]
单击添加后,在 From 输入框的第二行中,需要限制用户添加小于等于 5 的值(这意味着这些值已经输入) .
这样是无效的,
{
"distance": [
{
"from": 0,
"to": 5
},
{
"from": 5,
"to": 10
}
]
}
此处"from": 5,
或"from": 4(or)3(or)2(or)1
,第二行中的任何内容均无效..
只有 6 和大于 6 才有效。
同样,对于每一行,它都需要检查前一行的值,并且需要进行验证。
请帮助我实现这种限制用户输入前一行的值(或)小于当前行的起始值的验证类型。
工作示例: https://stackblitz.com/edit/disable-group-control-value-on-another-control-value-for-j58atx
编辑:
尝试输入更改,例如
<input type="number" (input)="onInputChange($event.target.value)" placeholder="From" formControlName="from">
在 link https://stackblitz.com/edit/disable-group-control-value-on-another-control-value-for-ymfpkj 但不确定我是否正确..
此程序如有错误请修改
只需要使用一个customValidation(我在同一个组件中选择验证
ngOnInit() {
this.form = this.fb.group({
distance: this.fb.array([], this.distanceValidator()),
});
this.addRow()
}
distanceValidator() {
return (fa: FormArray) => {
let ok = true;
let ok2 = fa.value.length ? (!fa.value[0].to || !fa.value[0].from) || fa.value[0].to > fa.value[0].from : true;
if (!ok2)
return { error: "from greater than to" }
for (let i = 1; i < fa.value.length; i++) {
if (fa.value[i].from && fa.value[i].to )
{
ok = (fa.value[i].from > fa.value[i - 1].to || fa.value[i].to < fa.value[i - 1].from);
ok2 = (fa.value[i].to > fa.value[i].from);
if (!ok)
return { error: "from/to yet included" }
if (!ok2)
return { error: "from greater than to" }
}
}
return ok && ok2 ? null : !ok?{ error: "from yet included" }:{ error: "from greater than to" }
}
}
您可以像另一个人一样看到错误
<div *ngIf="form.get('distance')?.errors">
{{form.get('distance')?.errors.error}}
</div>
参见 [stackblitz 分叉][1]
最后我决定把这两个条件分开。见 new stackblitz
ngOnInit() {
this.form = this.fb.group({
distance: this.fb.array([], this.distanceValidator()),
});
this.addRow()
}
addRow() {
const control = this.form.controls.distance as FormArray;
control.push(this.fb.group({
from: ['', Validators.required],
to: ['', Validators.required]
}, { validator: this.greaterValidator() }));
}
setDefault() {
const control = this.form.controls.distance as FormArray;
this.default.forEach(data => {
control.push(this.fb.group({
from: [data.from, Validators.required],
to: [data.to, Validators.required]
}, { validator: this.greaterValidator() }));
});
}
greaterValidator() {
return (fa: FormGroup) => {
return fa.value.to && fa.value.to < fa.value.from ? { error: "from greater than to" } : null;
}
}
distanceValidator() {
return (fa: FormArray) => {
let ok = true;
for (let i = 1; i < fa.value.length; i++) {
ok = (!fa.value[i].from || fa.value[i].from > fa.value[i - 1].to) && (!fa.value[i].to || fa.value[i].to > fa.value[i - 1].from);
if (!ok)
return { error: "from/to yet included", index: i }
}
return null
}
}
还有.html
<form [formGroup]="form">
<button (click)="addRow()">Add</button>
<div formArrayName="distance" >
<div
*ngFor="let item of form.get('distance').controls; let i = index"
[formGroupName]="i"
style="display: flex">
<input type="number"
placeholder="From"
formControlName="from">
<div>
<input type="number"
placeholder="To"
formControlName="to">
</div>
<span *ngIf="item.errors">*</span>
<span *ngIf="form.get('distance')?.errors && form.get('distance')?.errors.index==i">**</span>
</div>
</div>
<div *ngIf="form.get('distance')?.errors">{{form.get('distance')?.errors.error}}</div>
<br><br>
<button type="submit" [disabled]="!form.valid"> Submit </button>
</form>
<button (click)="setDefault()"> Set Default Values </button>
更新:其实只有在发现错误的时候才控制更多。 此外,如果 from 和 to before 为空,则不要报错。为了避免这种情况,我们可以 "convert" 编号,写作
let ok = (!fa.value[i].from || fa.value[i].from > +fa.value[i - 1].to)
&& (!fa.value[i].to || fa.value[i].to > +fa.value[i - 1].from);
(参见+fa.value[i-1].to 和+fa.value[i-1].from
中的“+”好吧,当我们决定我们发送的错误时,假设您有 6 行,位置 0、位置 3 和位置 4 的行(0 是第一行)发送一个错误,如
{error:"there are errors",indexError:",0,3,4,"}
这允许在*ngFor里面写一些像
<span *ngIf="form.get('distance')?.errors &&
form.get('distance')?.errors.indexError.indexOf(','+i+',')>=0">
**
</span>
嗯,我们的 distanceValidator 变成了这样
distanceValidator() {
return (fa: FormArray) => {
let indexError:string="";
for (let i = 1; i < fa.value.length; i++) {
let ok = (!fa.value[i].from || fa.value[i].from > +fa.value[i - 1].to) && (!fa.value[i].to || fa.value[i].to > +fa.value[i - 1].from);
if (!ok)
indexError+=','+i;
}
return indexError?{error:"there are errors",indexError:indexError+','}:null
}
有人会认为 return 错误数组更好,但这不允许以简单的方式知道有错误的行。有些像 errors.find(x=>x.id==i) 不起作用,因为我们不能在插值中使用查找。
确实只比较了一行和之前的中间行。可以在使用 for (let j=i-1;j>0;j++){ok=ok && ...}- 之前检查所有内容,但我认为这不是必需的,我们必须在代码中吝啬。请记住,函数 distanceValidator 被执行了几次 再看一个stackblitz