Angular-FormArray: создание табличной формы из двумерного массива Javascript - PullRequest
0 голосов
/ 16 октября 2019
  • Мне нужно создать форму таблицы с Angular, которая основана на простом 2-мерном массиве массивов.
  • Структура данных проста, но данные в ячейках взаимозависимы. Доступ к отдельным ячейкам осуществляется только с помощью индексов, например, row:1, col:0.
  • Должны быть определены пользовательские валидаторы на уровне ячеек. Кроме того, могут быть валидаторы для строк и столбцов.

Я пробовал различные способы определить FormArray, содержащий массив FormControl s. Но я не уверен, как получить доступ к соответствующим FormControl только по индексам строк и столбцов в шаблоне Angular.

Модель

[
  ['a', 'b'],
  ['c', 'd']
]

FormGroup

  form = new FormGroup({
    rows: new FormArray([...])
  });

Ожидаемый результат

Я пробовал разные вещи, похожие на это:

  <form [formGroup]="form"">
    <div formArrayName="rows">
      <div 
        *ngFor="let row of rows.controls; let rowIndex = index" [formGroupName]="rowIndex">
        <div formArrayName="cols">
          <div
            *ngFor="let col of form.get('cols').controls; let colIndex = index"
            [formGroupName]="colIndex">
            <input [formControlName]="colIndex" />
          </div>
        </div>
      </div>
    </div>
  </form>

Ответы [ 2 ]

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

Шаблонные формы сделают вашу жизнь намного проще.

Просто привязайте непосредственно к самому массиву.

<form>
  <div *ngFor="let row of data;let i=index">
    <input [name]="prop1_ + i" [(ngModel)]="row.prop1">
    <input [name]="prop2_ + i" [(ngModel)]="row.prop2">
  </div>
</form>
0 голосов
/ 16 октября 2019

Даббел, если у вас есть Array of Array, создайте FormArrays из FormArrays (извините за шутку)

Хорошо, представьте, что у вас есть данные = [['a', 'b'], ['c ',' d ']]

Вы можете в ngOnInit создать форму массива FormArray, например

//At firs a empty FormArray
this.formArray = new FormArray([]);
//with each element of data
this.data.forEach(x => {
  //x is e.g.['a','b']
  //we create a emptt FormArray
  const obj = new FormArray([]);
  //add a FormControl
  x.forEach(y => {
    obj.push(new FormControl(y));
  });
  //and push in the formArray
  this.formArray.push(obj);
});

, или сократить, используя карту, например

this.formArray=new FormArray(
  this.data.map(x=>new FormArray(
    x.map(y=>new FormControl(y))))
)

Ну, какуправлять FormArray вне FormGroup? Если наш FormArray является FormArray для FormGroup, мы в общем случае создаем

 <!--yes we can use [formGroup] with a FormArray-->
<form [formGroup]="formArray">
   <!--iterate over the formArray.controls, that is a formGroup-->
  <div *ngFor="let group of formArray.controls;let i=index">
     <div [formGroup]="group">
       <input formControlName="name">
        ...
     </div>
  </div>
</form>

. Итак, наш formArray является FormArray для FormArray, но помните, что мы используем [formGroup] с массивом и перебираем formArray.controls.

<form [formGroup]="formArray">
    <div *ngFor="let subarray of formArray.controls;let i=index">
        <div [formGroup]="subarray">
            <ng-container *ngFor="let control of subarray.controls;let j=index">
                <input [formControl]="control">{{control.invalid?"*":""}}
       </ng-container>
        </div>
    </div>
</form>

ПРИМЕЧАНИЕ. Я использую <ng-container> или <div>, чтобы не создавать зависимые элементы div. (Мы не можем поместить * ngFor в собственный вход, потому что, следовательно, у нас не может быть доступа к control.invalid

Ну, так как вы хотите создать Validators, мы немного меняемся, когда создаем formGroup длявключите валидаторы, я поставил "дурак" пример

this.formArray=new FormArray(
  this.data.map(x=>new FormArray(
    x.map(y=>new FormControl(y,Validators.required)),
    this.rowValidator())),this.arrayValidator()
)

А наши валидаторы могут быть как

  rowValidator()
  {
    return (array:FormArray)=> {
      const invalid:boolean=array.value.
             filter((x,index)=>array.value.indexOf(x)!=index).length>0
      return invalid?{error:'must be different'}:null
    }
  }
  arrayValidator()
  {
      return (array:FormArray)=> {
        let arrayJoin="";
        array.value.forEach(x=>arrayJoin+=x.join(''))
        return arrayJoin=="abcd"?null:{error:'must be a,b,c,d'}
      }
  }

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

ПРИМЕЧАНИЕ: В реальном приложении мы не использовали так много валидаторов. Учитывайте стоимость этого валидатора при работе приложения

...