Angular 反应式表单验证和数据形成问题
Angular Reactive form validation and data formation issue
尝试至少对 select 个 一个 项目添加验证 mat-select multipe option
。目前在页面加载时显示错误消息,直到用户 select 从 select 选项中选择一项,该选项工作正常。
期望:
当 i select all 或 single select 时,错误消息应该消失。 (预期且工作正常)。
但是发生了什么:
当我删除select selected 单个项目时,未显示必需的错误消息。
不知道我做错了什么。
skillForm.component.ts
skillList = [
{ skillId: '0', skillName: 'JS' },
{ skillId: '1', skillName: 'TS' },
{ skillId: '2', skillName: 'JAVA' },
{ skillId: '3', skillName: '.Net' },
];
@ViewChild('pickAllCourse') private pickAllCourse: MatOption;
trainerForm = FormGroup;
constructor(public formBuilder: FormBuilder) { }
this.trainerForm = this.formBuilder.group({
selectedSkills :['', Validators.required, Validators.minLength(1)]
})
pickAll(): void {
if(this.pickAllCourse.selected) {
this.trainerForm.controls.selectedSkills.patchValue([...this.skillList.map((item) => item.deviceId), 0]);
} else {
this.trainerForm.controls.selectedSkills.patchValue([]);
}
}
selectOneItem(all): any {
if (this.pickAllCourse.selected) {
this.pickAllCourse.deselect();
return false;
}
if (this.trainerForm.controls.selectedSkills.value.length === this.skillList.length) {
this.pickAllCourse.select();
}
}
onSubmit(): void{
console.log('form value', this.trainerForm.value)
//
}
skillForm.component.html
<mat-form-field class="selectedSkills">
<mat-select multiple ngDefaultControl formControlName="selectedSkills"
placeholder="Select Device Type">
<mat-option #pickAllCourse (click)="pickAll()" [value]="0">All</mat-option>
<mat-option *ngFor="let i of skillList" [value]="i.deviceId"
(click)="selectOneItem(pickAllCourse.viewValue)">{{ i.skillName }}
</mat-option>
</mat-select>
<span class="text-danger" *ngIf="trainerForm.controls['selectedSkills '].invalid ">This field is required</span>
</mat-form-field>
此外,我需要帮助来了解如何在为后端提交表单时构建如下所示的对象。
skillList: [
{skillId: '0'},
{skillId: '1'}
];
当我执行 console.log this.trainerForm.value
时,我看到 skillList: ['0']
问题和疑虑
问题 1:
trainerForm.controls['selectedSkills ']
.
上的额外间距存在拼写错误
<span class="text-danger" *ngIf="trainerForm.controls['selectedSkills '].invalid ">This field is required</span>
问题 2:
如果表单控件需要多个 Validators
,您应该 用数组 将它们分组。
this.trainerForm = this.formBuilder.group({
selectedSkills :['', Validators.required, Validators.minLength(1)]
})
更改为:
this.trainerForm = this.formBuilder.group({
selectedSkills :['', [Validators.required, Validators.minLength(1)]]
})
关注1
从 HTML 和 Typescript 部分,selectedSkills
将 return 一个 number
的数组,但不是 Object
的数组。当您使用 item.deviceId
(return string
) 并且 deviceId
不存在于 skillLists
的 Object
中。我假设您使用的是 item.skillId
.
pickAll(): void {
if(this.pickAllCourse.selected) {
this.trainerForm.controls.selectedSkills.patchValue([...this.skillList.map((item) => item.deviceId), 0]);
} else {
this.trainerForm.controls.selectedSkills.patchValue([]);
}
}
<mat-option *ngFor="let i of skillList" [value]="i.deviceId"
(click)="selectOneItem(pickAllCourse.viewValue)">{{ i.skillName }}
</mat-option>
因此,当你console.log(this.trainerForm.value)
时,它会显示:
{ selectedSkills: [1, 2, 3] }
解决方案
- 对于使用
*ngFor
生成的 <mat-option>
,将 [value]="{ skillId: i.skillId }"
设置为 return 选择值作为 object
。
- 为您的
<mat-select>
添加 compareWith
。目的是比较 this.trainerForm.controls.selectedSkills
与 [value]="{ skillId: i.skillId }"
到 check/uncheck 选项时 select/deselect All.
<mat-form-field class="selectedSkills">
<mat-select
multiple
ngDefaultControl
formControlName="selectedSkills"
placeholder="Select Device Type"
[compareWith]="compareFn"
>
<mat-option #pickAllCourse (click)="pickAll()" [value]="0"
>All</mat-option
>
<mat-option
*ngFor="let i of skillList"
[value]="{ skillId: i.skillId }"
(click)="selectOneItem(pickAllCourse.viewValue)"
>{{ i.skillName }}
</mat-option>
</mat-select>
<span
class="text-danger"
*ngIf="trainerForm.controls['selectedSkills'].invalid"
>This field is required</span
>
</mat-form-field>
- 如问题 2.
中所述,在数组 []
中设置多个 Validators
pickAll()
到 patchValue
对于 this.trainerForm.controls.selectedSkills
作为 { skillId: item.skillId }
Object
.
onSubmit()
在将表单值传递给 API 之前,请确保仅使用 { skillId: item.skillId }
Object
过滤 skillSets
值。
compareFn
用于将选定的 skillSets
值与每个 <mat-option>
值进行比较。因此,当 Select All 时,所有 <mat-option>
将被选中,反之亦然,如 (2).
trainerForm: FormGroup;
ngOnInit() {
this.trainerForm = this.formBuilder.group({
selectedSkills: ['', [Validators.required, Validators.minLength(1)]],
});
}
pickAll(): void {
if (this.pickAllCourse.selected) {
this.trainerForm.controls.selectedSkills.patchValue([
...this.skillList.map((item) => {
return {
skillId: item.skillId
};
}),
0,
]);
} else {
this.trainerForm.controls.selectedSkills.patchValue([]);
}
}
onSubmit(): void {
console.log('form value', this.trainerForm.value);
let postFormValue: any = {
...this.trainerForm.value,
selectedSkills: this.trainerForm.value.selectedSkills.filter(
(x: any) => typeof x === 'object'
),
};
console.log(postFormValue);
}
compareFn(obj1: any, obj2: any): boolean {
return obj1 && obj2 ? obj1.skillId === obj2.skillId : obj1 === obj2;
}
尝试至少对 select 个 一个 项目添加验证 mat-select multipe option
。目前在页面加载时显示错误消息,直到用户 select 从 select 选项中选择一项,该选项工作正常。
期望:
当 i select all 或 single select 时,错误消息应该消失。 (预期且工作正常)。
但是发生了什么:
当我删除select selected 单个项目时,未显示必需的错误消息。
不知道我做错了什么。
skillForm.component.ts
skillList = [
{ skillId: '0', skillName: 'JS' },
{ skillId: '1', skillName: 'TS' },
{ skillId: '2', skillName: 'JAVA' },
{ skillId: '3', skillName: '.Net' },
];
@ViewChild('pickAllCourse') private pickAllCourse: MatOption;
trainerForm = FormGroup;
constructor(public formBuilder: FormBuilder) { }
this.trainerForm = this.formBuilder.group({
selectedSkills :['', Validators.required, Validators.minLength(1)]
})
pickAll(): void {
if(this.pickAllCourse.selected) {
this.trainerForm.controls.selectedSkills.patchValue([...this.skillList.map((item) => item.deviceId), 0]);
} else {
this.trainerForm.controls.selectedSkills.patchValue([]);
}
}
selectOneItem(all): any {
if (this.pickAllCourse.selected) {
this.pickAllCourse.deselect();
return false;
}
if (this.trainerForm.controls.selectedSkills.value.length === this.skillList.length) {
this.pickAllCourse.select();
}
}
onSubmit(): void{
console.log('form value', this.trainerForm.value)
//
}
skillForm.component.html
<mat-form-field class="selectedSkills">
<mat-select multiple ngDefaultControl formControlName="selectedSkills"
placeholder="Select Device Type">
<mat-option #pickAllCourse (click)="pickAll()" [value]="0">All</mat-option>
<mat-option *ngFor="let i of skillList" [value]="i.deviceId"
(click)="selectOneItem(pickAllCourse.viewValue)">{{ i.skillName }}
</mat-option>
</mat-select>
<span class="text-danger" *ngIf="trainerForm.controls['selectedSkills '].invalid ">This field is required</span>
</mat-form-field>
此外,我需要帮助来了解如何在为后端提交表单时构建如下所示的对象。
skillList: [
{skillId: '0'},
{skillId: '1'}
];
当我执行 console.log this.trainerForm.value
时,我看到 skillList: ['0']
问题和疑虑
问题 1:
trainerForm.controls['selectedSkills ']
.
<span class="text-danger" *ngIf="trainerForm.controls['selectedSkills '].invalid ">This field is required</span>
问题 2:
如果表单控件需要多个 Validators
,您应该 用数组 将它们分组。
this.trainerForm = this.formBuilder.group({
selectedSkills :['', Validators.required, Validators.minLength(1)]
})
更改为:
this.trainerForm = this.formBuilder.group({
selectedSkills :['', [Validators.required, Validators.minLength(1)]]
})
关注1
从 HTML 和 Typescript 部分,selectedSkills
将 return 一个 number
的数组,但不是 Object
的数组。当您使用 item.deviceId
(return string
) 并且 deviceId
不存在于 skillLists
的 Object
中。我假设您使用的是 item.skillId
.
pickAll(): void {
if(this.pickAllCourse.selected) {
this.trainerForm.controls.selectedSkills.patchValue([...this.skillList.map((item) => item.deviceId), 0]);
} else {
this.trainerForm.controls.selectedSkills.patchValue([]);
}
}
<mat-option *ngFor="let i of skillList" [value]="i.deviceId"
(click)="selectOneItem(pickAllCourse.viewValue)">{{ i.skillName }}
</mat-option>
因此,当你console.log(this.trainerForm.value)
时,它会显示:
{ selectedSkills: [1, 2, 3] }
解决方案
- 对于使用
*ngFor
生成的<mat-option>
,将[value]="{ skillId: i.skillId }"
设置为 return 选择值作为object
。 - 为您的
<mat-select>
添加compareWith
。目的是比较this.trainerForm.controls.selectedSkills
与[value]="{ skillId: i.skillId }"
到 check/uncheck 选项时 select/deselect All.
<mat-form-field class="selectedSkills">
<mat-select
multiple
ngDefaultControl
formControlName="selectedSkills"
placeholder="Select Device Type"
[compareWith]="compareFn"
>
<mat-option #pickAllCourse (click)="pickAll()" [value]="0"
>All</mat-option
>
<mat-option
*ngFor="let i of skillList"
[value]="{ skillId: i.skillId }"
(click)="selectOneItem(pickAllCourse.viewValue)"
>{{ i.skillName }}
</mat-option>
</mat-select>
<span
class="text-danger"
*ngIf="trainerForm.controls['selectedSkills'].invalid"
>This field is required</span
>
</mat-form-field>
- 如问题 2. 中所述,在数组
pickAll()
到patchValue
对于this.trainerForm.controls.selectedSkills
作为{ skillId: item.skillId }
Object
.onSubmit()
在将表单值传递给 API 之前,请确保仅使用{ skillId: item.skillId }
Object
过滤skillSets
值。compareFn
用于将选定的skillSets
值与每个<mat-option>
值进行比较。因此,当 Select All 时,所有<mat-option>
将被选中,反之亦然,如 (2).
[]
中设置多个 Validators
trainerForm: FormGroup;
ngOnInit() {
this.trainerForm = this.formBuilder.group({
selectedSkills: ['', [Validators.required, Validators.minLength(1)]],
});
}
pickAll(): void {
if (this.pickAllCourse.selected) {
this.trainerForm.controls.selectedSkills.patchValue([
...this.skillList.map((item) => {
return {
skillId: item.skillId
};
}),
0,
]);
} else {
this.trainerForm.controls.selectedSkills.patchValue([]);
}
}
onSubmit(): void {
console.log('form value', this.trainerForm.value);
let postFormValue: any = {
...this.trainerForm.value,
selectedSkills: this.trainerForm.value.selectedSkills.filter(
(x: any) => typeof x === 'object'
),
};
console.log(postFormValue);
}
compareFn(obj1: any, obj2: any): boolean {
return obj1 && obj2 ? obj1.skillId === obj2.skillId : obj1 === obj2;
}