typescript - Angular UI fryser när man använder formArray med Material Auto-complete inuti Mat-table


Jag använder en mat-table inuti en popup. Inuti mat-tabellen kommer det att finnas rader med mat-autocomplete. Saken är den att jag behöver lägga till rader dynamiskt. Jag använder ett formGroup inuti vilket det finns en formArray.

detta kommer att vara modellen för FormGroup

   {
  formArray:
    [
      {
         name:"someName",
         material:"someMaterial",
         quantity:5
      },
      {
         name:"someName2",
         material:"someMaterial",
         quantity:5
      },    
    ]

}

Först kommer rutnätet att vara tomt men när jag klickar på en knapp, infogar det en formGroup i formArray (som är datakälla för rutnätet). Men när det händer fryser användargränssnittet helt och jag kan inte göra någonting.

här är HTML-filen Kod

<form [formGroup]="positionFormGroup">
    <div class="card-body" style="height: 500px; overflow: auto;"  >
        <table class="full-width" style="overflow: scroll;" mat-table [dataSource]="this.positionFormGroup.get('positionInfos').value" formArrayName = "positionInfos">

            <!-- Material Column -->
            <ng-container matColumnDef="Material">
                <th mat-header-cell *matHeaderCellDef class="text-center align-column">
                    <p [innerHTML]=" 'MachineCapacity.Grid_Label_IdMaterial' | translate"></p>
                </th>
                <td mat-cell *matCellDef="let data; let i = index" [formGroupName]="i">
                    {{data.idMaterial}}

                    <input type="text" formControlName="idMaterial" [matAutocomplete]="materialAuto">
                    <mat-autocomplete #materialAuto="matAutocomplete">
                        <mat-option *ngFor="let option of materialFilteredOptions | async" [value]="option.description"
                            class="auto-option">
                            {{option.description}}
                        </mat-option>
                    </mat-autocomplete>

                </td>
            </ng-container>

            <!-- Quantity Column -->
            <ng-container matColumnDef="Quantity">
                <th mat-header-cell *matHeaderCellDef class="text-center align-column">
                    <p [innerHTML]=" 'MachineCapacity.Grid_Label_Quantity' | translate"></p>
                </th>
                <td mat-cell *matCellDef="let data">
                    {{data.quantity}}
                </td>
            </ng-container>

Jag kan spåra problemet. Det händer på grund av referensen jag använder för mat-auto complete. Det fungerar antingen när jag tar bort matAutoComplete-referensen från input-taggen eller när jag ändrar formControlName.

här är TS-koden :

  ngOnInit(): void {

   // this.positionInfos = new FormArray([]);
    this.positionFormGroup = this.formBuilder.group({
      positionInfos: new FormArray([])
    });

    //this.positionFormGroup.

  }

  addMaterial(){
    let data  = {
      rowID :'f',
      position : 'f',
      idMaterial:'f',
      quantity: 'f',
      isDeleted: 'f',
      isActive:true
    }
    

    this.positionFormGroup.get('positionInfos')?.push(this.formBuilder.group(data))
    //console.log( this.positionFormGroup.get('positionInfos').value)
  }

Vänligen låt mig veta om jag missar något, tack på förhand

Svar #1

Inte relaterat till referensproblemet och UI fryser inte alls.

Det hände på grund av ändringsdetektering, tror jag. Därför kände vi av en frusning i användargränssnittet.

Precis vid denna punkt, [dataSource]="this.positionFormGroup.get('positionInfos').value" triggar det ändringsdetekteringen oändligt många gånger

Jag vet inte, varför det utlöste oändligt många gånger.

Har redan ett svar för inbäddade formulärgrupper.

html

<form [formGroup]="positionFormGroup" novalidate>
  <table formArrayName="positionInfos">

    <div *ngFor="let data of control; let i = index">
      <div [formGroupName]="i">

        <input type="text" formControlName="idMaterial" [matAutocomplete]="materialAuto">
        <mat-autocomplete #materialAuto="matAutocomplete">
          <mat-option *ngFor="let option of materialFilteredOptions | async" [value]="option.description">
            {{option.description}}
          </mat-option>
        </mat-autocomplete>
      </div>
    </div>

  </table>
</form>

ts

export class AppComponent {
  positionFormGroup: FormGroup;
  materialControl: FormControl = new FormControl('');
  materialFilteredOptions: Observable<{ description: string; }[]>;
  options = [
    { description: 'item1' },
    { description: 'item2' },
    { description: 'item3' },
    { description: 'item4' }
  ]

  control: any;
  constructor(private formBuilder: FormBuilder) {
  }

  ngOnInit(): void {
    this.materialFilteredOptions = this.materialControl.valueChanges
      .pipe(
        startWith(''),
        map(value => this.options)
      );
    this.positionFormGroup = this.formBuilder.group({
      positionInfos: new FormArray([])
    });

    this.addMaterial();
    this.control = this.getControls().controls;
  }


  addMaterial() {
    (this.positionFormGroup.get('positionInfos') as FormArray).push(this.formBuilder.group({
      rowID: '0',
      position: '0',
      idMaterial: 'item1',
      quantity: 1,
      isDeleted: false,
      isActive: true
    }));
  }

  confirm(){
    console.log( this.positionFormGroup.get('positionInfos').value)
  }

  getControls(){
    console.log( (this.positionFormGroup.get('positionInfos') as FormArray));
    return (this.positionFormGroup.get('positionInfos') as FormArray);
  }