最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Expandable Rows in p-table with nested FormArray in Angular - Stack Overflow

programmeradmin3浏览0评论

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.

In my ponent 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],
        entarios: ['',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" (pleteMethod)="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="entarios"></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

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.

In my ponent 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],
        entarios: ['',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" (pleteMethod)="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="entarios"></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

Share Improve this question edited Jun 15, 2022 at 16:50 Wilmer asked Jun 15, 2022 at 4:25 WilmerWilmer 731 silver badge8 bronze badges 2
  • Colud you reproduce it on stackblitz, it will be more easier to help you – Yan Koshelev Commented Jun 15, 2022 at 9:02
  • Thanks for answering @YanKoshelev, I edited my question and added the example in stackblitz – Wilmer Commented Jun 15, 2022 at 16:52
Add a ment  | 

2 Answers 2

Reset to default 4

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

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>

发布评论

评论列表(0)

  1. 暂无评论