Home > Software design >  Expandable Rows in p-table with nested FormArray in Angular
Expandable Rows in p-table with nested FormArray in Angular

Time:06-16

I am working with Prime-ng, and I need to expand my registration forms with FormArray and continue to dynamically display other child forms. The image shows what I'm trying to achieve. enter image description here

In my component I have:

initFrmCotizacion(){
    this.frmCotizacion = this.build.group({
        ingresoDetalle: null,
        descripcion: ['',Validators.required],
        cotizacionArray: this.build.array([])
    })
}

datosCotizacionArray(): FormArray {
    return this.frmCotizacion.get('cotizacionArray') as FormArray;
}

anadirCotizacionArray() {
    this.datosCotizacionArray().push(this.newCotizacionArray());
}

newCotizacionArray(){
    return this.build.group({
        idd:   this.dataKey, //<- this use in dataKey to cotizacionArray
        adjunto: [null,Validators.required],
        proveedor: [1,Validators.required],
        cantidad: [1,Validators.required],
        precioUnitario: [1,Validators.required],
        comentarios: ['',Validators.required],
        rangosArray: this.build.array([])
    });   
}

removeFeature(index: number) {
    this.datosCotizacionArray().removeAt(index);
    this.myFiles.splice(index,1);
}       

anadirRangosArray(index) {
    this.datosRangosArray(index).push( this.newRangosArray() );
}

newRangosArray() {
    return this.build.group({
        id:   this.dataKey2, //<- this use in dataKey to rangosArray
        min: [null, Validators.required],
        max: [null, Validators.required],
        precio: [null, Validators.required]
    });
}

datosRangosArray(index: number): FormArray{
    return this.datosCotizacionArray()
        .at(index)
        .get('rangosArray') as FormArray;
}

In my html I have:

<p-button label="Nueva cotización" icon="pi pi-plus" (click)="anadirCotizacionArray()" styleClass="p-button-sm"></p-button>
<form [formGroup]="frmCotizacion" (ngSubmit)="saveCotizacion()">
    <div  formArrayName="cotizacionArray">
        <p-table styleClass="p-datatable-sm p-datatable-gridlines" dataKey="idd"
            [value]="datosCotizacionArray().controls" responsiveLayout="stack">
            <ng-template pTemplate="header">
                <tr>
                    <th style="width: 3rem"></th>
                    <th>Archivo</th>
                    <th>Proveedor</th>
                    <th>Cantidad</th>
                    <th>Precio U.</th>
                    <th>Precio T.</th>
                    <th>Comnetarios</th>
                    <th style="width: 100px;"></th>
                </tr>
            </ng-template>
            <ng-template pTemplate="body" let-control let-expanded="expanded" let-i="rowIndex">
                <tr [formGroupName]="i">
                    <td>
                        <button type="button" pButton pRipple [pRowToggler]="control" 
                             
                            [icon]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'"></button>
                    </td>                                               
                    <td>
                        <input style="width: 70%;" id="adjunto" type="file" multiple name="file" accept="application/pdf" 
                            formControlName="adjunto" pInputText placeholder="adjunto" 
                            (change)="onFileChange($event)">
                    </td>
                    <td>
                        <p-autoComplete formControlName="proveedor" [style]="{width: '100%'}" z-index=""
                            [suggestions]="filteredCountries" (completeMethod)="filterCountry($event)"
                            field="name" [minLength]="1" [dropdown]="true">
                            <ng-template let-country pTemplate="item">
                                <div >
                                    <div>{{country.name}}</div>
                                </div>
                            </ng-template>                                      
                        </p-autoComplete>                                                           
                    </td>
                    <td>
                        <p-inputNumber [inputStyle]="{width: '100%'}" #cant id="cantidad" formControlName="cantidad" placeholder="Cantidad" mode="decimal" [useGrouping]="false" [min]="0"></p-inputNumber>
                    </td>
                    <td>
                        <p-inputNumber [inputStyle]="{'text-align': 'right', width: '100%'}" 
                        #prec id="preciounitario" formControlName="precioUnitario" placeholder="Precio unitario" 
                        mode="decimal" [min]="1" [maxFractionDigits]="5"></p-inputNumber>
                    </td>
                    <td>
                        {{ cant.value *  prec.value }}
                    </td>
                    <td>
                        <textarea pInputTextarea formControlName="comentarios"></textarea>
                    </td>
                    <td style="width: 100px">
                        <button pButton pRipple type="button" (click)="removeFeature(i)" icon="pi pi-times" ></button>
                        <button pButton pRipple type="button" (click)="anadirRangosArray(i)" icon="pi pi-check" ></button>
                    </td>                                                   
                </tr>
            </ng-template>
            <ng-template pTemplate="rowexpansion" let-conti>
                <tr>
                    <td colspan="8">
                        <div >
                            <p-table [value]="datosRangosArray(0).controls" dataKey="id">
                                <ng-template pTemplate="header">
                                    <tr>
                                        <th>Mínimo</th>
                                        <th>Máximo</th>
                                        <th>Precio</th>
                                        <th></th>
                                    </tr>
                                </ng-template>
                                <ng-template pTemplate="body"  let-rangos let-j="index" >
                                    <tr [formGroupName]="j">
                                        <td>
                                            <p-inputNumber [inputStyle]="{'text-align': 'right', width: '100%'}" 
                                                id="min" formControlName="min" placeholder="Cantidad mínima" 
                                                mode="decimal" [min]="1" [maxFractionDigits]="5"></p-inputNumber>
                                        </td>
                                        <td>
                                            <p-inputNumber [inputStyle]="{'text-align': 'right', width: '100%'}" 
                                                id="max" formControlName="max" placeholder="Cantidad máxima" 
                                                mode="decimal" [min]="1" [maxFractionDigits]="5"></p-inputNumber>                                                                       
                                        </td>
                                        <td>
                                            <p-inputNumber [inputStyle]="{'text-align': 'right', width: '100%'}" 
                                            id="precio" formControlName="precio" placeholder="Precio" 
                                            mode="decimal" [min]="1" [maxFractionDigits]="5"></p-inputNumber>
                                        </td>
                                        <td><p-button type="button" icon="pi pi-search"></p-button></td>
                                    </tr>
                                </ng-template>
                            </p-table>
                        </div>
                    </td>
                </tr>
            </ng-template>                                      
        </p-table>  
    </div>
    <br>
    <div >
        <div >
            <textarea rows="5" cols="60" placeholder="Descripción" formControlName="descripcion" pInputTextarea></textarea>
        </div>
    </div>
    <div >
        <button pButton icon="pi pi-save" label="Rechazar" ></button>
        <button pButton icon="pi pi-trash" label="Guardar" [disabled]="!frmCotizacion.valid" ></button>
    </div>                              
</form>

My problem is that I need to dynamically add the child forms. The parent forms as well as the child forms must be sent to a database with a button, that means that I manually assign the values to "id" which I then use for the dataKey="id". Adding the parent form works fine, but when expanding I need to retrieve

[formGroupName]="i"

it in my ng-template where I put the child forms. Currently I add the value zero to function

[value]="datosRangosArray(0).controls"

This work only for the index "0" in cotizacionArray. The error in the browser console is:

ERROR Error: Cannot find control with path: 'cotizacionArray -> ' Considering that the child forms must be in ng-template how would I go about getting the value of "i"

Please help me

The example in stackblitz

CodePudding user response:

You just need to handle controls by instances and I have added expand button.

datosRangosArray(formGroup: FormGroup): FormArray {
    return formGroup.get('rangosArray') as FormArray;;
  }

<p-table [value]="datosRangosArray(conti).controls" dataKey="id">

Stackblitz

  • Related