Проблема с проверкой угловой реактивной формы и формированием данных

#javascript #angular #typescript #angular-reactive-forms #angular-forms

Вопрос:

Пытаюсь добавить проверку хотя бы для выбора минимум одного элемента mat-select multipe option . В настоящее время отображается сообщение об ошибке при загрузке страницы, пока пользователь не выберет один элемент из опции выбора, который работает нормально.

ожидание:
Когда я выбираю all или single select, сообщение об ошибке должно исчезнуть. (ожидается и работает нормально).

Но что происходит:
Требуемое сообщение об ошибке не отображается, когда я отменяю выбор выбранного отдельного элемента.

Не знаю, что я делаю не так.

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

когда я делаю консоль.войдите this.trainerForm.value в систему, я вижу skillList: ['0']

Комментарии:

1. Не могли бы вы поделиться своим сообщением об ошибке?

2. ДА. Я уже обновил свой SO, @Batajus, который вы можете использовать под mat-select

3. Не уверен, что это проблема, но кое-что я видел. Когда вы инициализировали свою форму в файле TS, это selectedSkills =['', Validators.required, Validators.minLength(1)] , вероятно, должно быть selectedSkills: ['', Validators.required, Validators.minLength(1)] с a : вместо = .

4. @JasonWhite это не проблема. на самом деле это моя опечатка. см. Обновленный so. Спасибо

Ответ №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 (return string ) и deviceId не существует в Object for 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. Для <mat-option> сгенерированного с *ngFor помощью, установите [value]="{ skillId: i.skillId }" для возврата выбранного значения как object .
  2. Добавьте compareWith для вашего <mat-select> . Цель сравнения 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() patchValue для this.trainerForm.controls.selectedSkills as { skillId: item.skillId } Object .
  3. onSubmit() прежде чем передавать значение формы в API, убедитесь, что вы фильтруете skillSets значение { skillId: item.skillId } Object только с помощью.
  4. compareFn предназначен для сравнения выбранного skillSets значения с каждым <mat-option> значением. Следовательно, при выборе всех <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 amp;amp; obj2 ? obj1.skillId === obj2.skillId : obj1 === obj2;
}
 

Пример решения на StackBlitz

Комментарии:

1. Это потрясающе. то, как вы объяснили ошибку и реализацию, очень хорошо. это так чисто. следовательно, принимая это. Спасибо, приятель 🙂 @Ен Шун