Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expandable Rows in p-table with nested FormArray in Angular

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 class="card" 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" 
                            class="p-button-text p-button-rounded p-button-plain" 
                            [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 class="country-item">
                                    <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" class="p-button-rounded p-button-danger p-button-text p-mr-2 p-mb-2"></button>
                        <button pButton pRipple type="button" (click)="anadirRangosArray(i)" icon="pi pi-check" class="p-button-rounded p-button-danger p-button-text p-mr-2 p-mb-2"></button>
                    </td>                                                   
                </tr>
            </ng-template>
            <ng-template pTemplate="rowexpansion" let-conti>
                <tr>
                    <td colspan="8">
                        <div class="p-p-3">
                            <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 class="p-grid p-formgrid">
        <div class="p-col-12 p-mb-2 p-lg-4 p-mb-lg-0">
            <textarea rows="5" cols="60" placeholder="Descripción" formControlName="descripcion" pInputTextarea></textarea>
        </div>
    </div>
    <div class="p-dialog-footer ng-tns-c120-4 ng-star-inserted">
        <button pButton icon="pi pi-save" label="Rechazar" class="p-button-outlined p-button-danger p-mr-2 p-mb-2"></button>
        <button pButton icon="pi pi-trash" label="Guardar" [disabled]="!frmCotizacion.valid" class="p-button-outlined p-button-success p-mr-2 p-mb-2"></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

like image 810
Wilmer Avatar asked Nov 02 '25 03:11

Wilmer


2 Answers

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

like image 74
Yan Koshelev Avatar answered Nov 04 '25 17:11

Yan Koshelev


Another way to solve the problem is to pass [value]=arrayFormName.controls, and then use dataKey="value.id" or any other attribute.

What the p-table should do is concatenate the contents of [value] with dataKey.

While to solve the problem that all rows are expanded just add rowExpandMode="single"

Complete example


<p-table dataKey="value.id"
         rowExpandMode="single"
         [value]="fatturaDettagli.controls">
  <ng-template pTemplate="header">
    <tr>
      <th style="width: 3rem"></th>
      <th>Name</th>
    </tr>
  </ng-template>
  <ng-template pTemplate="body" let-rowData let-expanded="expanded" let-i="rowIndex">
    <tr [formGroupName]="i">
      <td>
        <button type="button" 
                pButton 
                [pRowToggler]="rowData"
                class="p-button-text">
      </td>
      <td>{{rowData.get('name').value}}</td>
    </tr>
  </ng-template>
</p-table>

like image 30
Luca Fulgenzi Avatar answered Nov 04 '25 16:11

Luca Fulgenzi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!