Проверка для предотвращения дублирования значений формы в угловых формах - PullRequest
0 голосов
/ 27 октября 2019

У меня есть несколько массивов форм, и мне нужна проверка, чтобы определенное поле в каждой строке формы было уникальным для всех массивов форм. Если какое-либо из значений появляется более одного раза, оба поля формы должны быть отмечены красным.

Мне удалось написать функцию, чтобы в случае каких-либо изменений в этих полях функция возвращала значение true / false. Но я не уверен, как использовать это для фактического процесса проверки.

component.html:

<div formArrayName="temperatureFormArr">
  <div class="row" *ngFor="let temperature of parentForm['controls'].detailForm['controls'].temperatureFormArr['controls']; let i=index"
    [formGroupName]="i">
    <div class="col-4">
      <mat-form-field appearance="outline" class="fex-input">
          <mat-label>Higher Level Function</mat-label>
        <input autocomplete = "off" matInput placeholder="Higher Level Function" (input)="testFunction(i, 'temperatureFormArr')" formControlName="higherLevelFunction">
      </mat-form-field>
    </div>
    <div class="col-6">
      <mat-form-field appearance="outline" class="fex-input">
          <mat-label>Description</mat-label>
        <input autocomplete = "off" matInput placeholder="Description" formControlName="description">
      </mat-form-field>
    </div>
  </div>
</div>

<div formArrayName="waterPressureFormArr">
  <div class="row" *ngFor="let waterPressure of parentForm['controls'].detailForm['controls'].waterPressureFormArr['controls']; let i=index"
    [formGroupName]="i">
    <div class="col-4">
      <mat-form-field appearance="outline" class="fex-input">
          <mat-label>Higher Level Function</mat-label>
        <input autocomplete = "off" matInput placeholder="Higher Level Function" (input)="testFunction(i, 'waterPressureFormArr')"  formControlName="higherLevelFunction">
      </mat-form-field>
    </div>
    <div class="col-6">
      <mat-form-field appearance="outline" class="fex-input">
          <mat-label>Description</mat-label>
        <input autocomplete = "off" matInput placeholder="Description" formControlName="description">
      </mat-form-field>
    </div>
  </div>
</div>

component.ts

  testFunction(i: any, typeOfArray: string) {
    var duplicateFlag = false;
    var testValue = this.parentForm['controls'].detailForm['controls'][typeOfArray].controls[i].value;
    for (let index = 0; index < this.parentForm['controls'].detailForm['controls'].temperatureFormArr.length; index++) {
      if(this.parentForm['controls'].detailForm['controls'].temperatureFormArr['controls'][index]
      .get('higherLevelFunction').value == testValue.higherLevelFunction && (index != i || typeOfArray != 'temperatureFormArr')) {
        duplicateFlag = true;
      }
    }
    for (let index = 0; index < this.parentForm['controls'].detailForm['controls'].waterPressureFormArr.length; index++) {    
      if(this.parentForm['controls'].detailForm['controls'].waterPressureFormArr['controls'][index]
      .get('higherLevelFunction').value == testValue.higherLevelFunction && (index != i || typeOfArray != 'waterPressureFormArr')) {
        duplicateFlag = true;
      }
    }
    return duplicateFlag;
  }

Для каждого нажатия клавиши вызывается эта функция, и выполняется проверка всех значений во всехдругие массивы форм, чтобы увидеть, есть ли дубликаты. Но как я могу изменить это так, чтобы я мог использовать эту функцию в качестве валидатора и пометить дублирующиеся поля ввода соответственно?

Ответы [ 2 ]

1 голос
/ 27 октября 2019

У вас есть два подхода при использовании проверок

1.-Подтвердите вызов элемента управления и вход (вход) для updateValueAndValidity остальных элементов управления. Это связано с тем, что при проверке элемента управления выполняется только проверка этого элемента управления.

Вы можете использовать функцию типа

  duplicateControlError(field) {
    return (control: FormControl) => {
      let result: boolean = false;
      const group = control.parent as FormGroup;
      if (group) {
        const values = control.parent.parent.value.map(x => x[field]);
        result = values.filter(x => x == control.value).length > 1;
      }
      return result ? { error: "duplicate" } : null;
    };
  }

и другую для updateValueAndValidity других элементов управления

  updateValidation(arrayName,field)
  {
    (this.form.get(arrayName) as FormArray).controls.forEach(
      group=>group.get(field).updateValueAndValidity()
    )
  }

.html становится похожим на

        <mat-form-field class="example-full-width">
            <input matInput placeholder="higherLevelFunction" formControlName="higherLevelFunction" (input)="updateValidation('temperatureFormArray','higherLevelFunction')">
<mat-error>Duplicate</mat-error>
</mat-form-field>

И вы создаете форму, подобную

  form = new FormGroup({
    temperatureFormArray: new FormArray(
      this.data.map(
        (x, index) =>
          new FormGroup({
            description: new FormControl(x.description),
            higherLevelFunction: new FormControl(
              x.higherLevelFunction,
              this.duplicateControlError("higherLevelFunction")
            )
          })
      )
    )
  });

Другой подход - создать собственный валидатор над FormArray

  duplicateError(field) {
    return (formArray: FormArray) => {
      let duplicate = [];
      formArray.value.forEach((x, index) => {
        if (formArray.value.filter(y => y[field] == x[field]).length > 1)
          duplicate.push(index);
      });
      return duplicate.length ? { error: duplicate } : null;
    };
  }

FormArray, который вы создаете как

form = new FormGroup({
    temperatureFormArray: new FormArray(
      this.data.map(
        (x, index) =>
          new FormGroup({
            description: new FormControl(x.description),
            higherLevelFunction: new FormControl(
              x.higherLevelFunction)
            )
          })
      ),
      this.duplicateError("higherLevelFunction")
    )
  });

Проблема с этим подходом заключается в том, что FormArray имеет ошибку. Если вход имеет только нормальный вход, мы можем использовать такие, как

    <div *ngIf="form.get('temperatureFormArray').errors?.error.indexOf(i)>=0">
      duplicate
    </div>

Но мы используем материал ввода, поэтому нам нужно изменить, когда вы пометите элемент управления как недействительный. Для этого нам нужно использовать собственный ErrorStateMatcher. Это только функция, которая заставляет mat-error показывать, если функция возвращает true. Нам нужно передать в качестве аргумента formArrayName и индекс, поэтому мы определили такие, как

export class DuplicateStateMatcher implements ErrorStateMatcher {
  constructor(private formArrayName:string,private index:number){}
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const formArray=form.form.get(this.formArrayName) as FormArray
    const error=formArray && formArray.errors?
    formArray.errors.error.indexOf(this.index)>=0:null
    return (control && error && (control.dirty || control.touched));
  }
}

и функцию в нашем компоненте, такую ​​как

  matcher(formArrayName,index)
  {
     return new DuplicateStateMatcher(formArrayName,index);
  }  

.html

        <mat-form-field class="example-full-width">
            <input matInput placeholder="higherLevelFunction" formControlName="higherLevelFunction" [errorStateMatcher]="matcher('temperatureFormArray',i)">
<mat-error>Duplicate</mat-error>
</mat-form-field>

Вы можете увидеть два подхода в stackblitz

0 голосов
/ 27 октября 2019

Угловые формы могут иметь специальные валидаторы. По сути, функция, которая выполняет логику, чтобы решить, является ли поле действительным или нет. Вот руководство по . Используйте ту же логику, что и в testFunction, и примените ее в качестве пользовательского валидатора. Один построен, примените его ко всем полям в массивах.

...