【问题标题】:Angular Reactive form validation and data formation issueAngular Reactive 表单验证和数据形成问题
【发布时间】:2021-12-09 17:44:16
【问题描述】:

尝试添加验证至少以从mat-select multipe option 中选择最少一个 项。目前在页面加载时显示错误消息,直到用户从选择选项中选择一项,这工作正常。

期望:
当我选择全部或单选时,错误消息应该消失。 (预期和工作正常)。

但是发生了什么:
当我取消选择选定的单个项目时,未显示所需的错误消息。

不知道我做错了什么。

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']

【问题讨论】:

  • 能否分享您的错误信息?
  • 是的。已经更新了我的 SO,@Batajus 你可以跨越mat-select
  • 不确定这是否是问题,但我看到了一些东西。当您在 TS 文件中初始化表单时,此 selectedSkills =['', Validators.required, Validators.minLength(1)] 可能应该是 selectedSkills: ['', Validators.required, Validators.minLength(1)]: 而不是 =
  • @JasonWhite 这不是问题。实际上这是我的错字。看到更新了。谢谢

标签: javascript angular typescript angular-reactive-forms angular-forms


【解决方案1】:

问题和疑虑

问题 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 将返回 number 的数组,而不是 Object 的数组。当您使用item.deviceId(返回string)时,deviceIdObject 中不存在skillLists。我假设您使用的是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] }

解决方案

  1. 对于使用*ngFor 生成的&lt;mat-option&gt;,设置[value]="{ skillId: i.skillId }" 以将选定的值返回为object
  2. 为您的&lt;mat-select&gt; 添加compareWith。用于比较 this.trainerForm.controls.selectedSkills[value]="{ skillId: i.skillId }" 以在全选/取消全选时选中/取消选中选项。
<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>
  1. 在数组[] 中设置多个Validators,如问题2中所述。
  2. pickAll()patchValuethis.trainerForm.controls.selectedSkills{ skillId: item.skillId } Object
  3. onSubmit() 在将表单值传递给 API 之前,请确保仅使用 { skillId: item.skillId } Object 过滤 skillSets 值。
  4. compareFn 用于将选定的skillSets 值与每个&lt;mat-option&gt; 值进行比较。因此,当全选时,所有&lt;mat-option&gt; 将被选中,反之亦然,如 (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;
}

Sample Solution on StackBlitz

【讨论】:

  • 太棒了。您解释错误和实施的方式非常好。这太干净了。因此接受它。谢谢队友 :) @Yong Shun
猜你喜欢
  • 1970-01-01
  • 2019-01-30
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
  • 2016-04-10
  • 1970-01-01
  • 2018-07-01
  • 2015-07-18
相关资源
最近更新 更多