如何在 mat-table 的可扩展行中构建动态表单?

How to build a dynamic form in a mat-table's expandable row?

我正在尝试构建一个 table 以允许我在其上执行多个任务;其中,我正在尝试实现在此处编辑记录信息的功能。

我的想法是像往常一样创建 mat-table,另外 expandable row 显示一个小表格,其中包含我可以编辑的字段和一个按钮来保存更改并更新table。但是我不确定如何实际构建它,因为我不确定如何为 table; 中的每一行构建反应式表单。我将无法在组件 TypeScript 文件中声明它,例如:

rowForm = new FormGroup({
            control1: new FormControl() 
         })

因为 table 中的每条记录都需要它。

 <table mat-table matSort [dataSource]="dataSource" class="table table-borderless admin-users-table" multiTemplateDataRows>
     <ng-container matColumnDef="name">
         <th mat-header-cell *matHeaderCellDef mat-sort-header> NAME </th>
         <td mat-cell *matCellDef="let user">
             <a href="javascript:" [routerLink]="['/setup/users', user._id]">
                 {{ user.name }}
             </a>
         </td>
     </ng-container>

     <ng-container matColumnDef="email">
         <th mat-header-cell *matHeaderCellDef mat-sort-header> EMAIL </th>
         <td mat-cell *matCellDef="let user">
             {{ user.email }}
         </td>
     </ng-container>

     <ng-container matColumnDef="id">
         <th mat-header-cell *matHeaderCellDef> USER ID </th>
         <td mat-cell *matCellDef="let user">
             {{ user._id }}
         </td>
     </ng-container>

     <ng-container matColumnDef="org">
         <th mat-header-cell *matHeaderCellDef mat-sort-header> ORGANIZATION </th>
         <td mat-cell *matCellDef="let user">
             {{ user.organization.name }}
         </td>
     </ng-container>
                
     <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
     <ng-container matColumnDef="expandedDetail">
         <td mat-cell *matCellDef="let element" class="py-0" [attr.colspan]="columnsToDisplay.length">
             <div class="user-element-detail"
                        [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
                  <div class="user-element-diagram">
                      <div class="user-element-position"> {{element.position}} </div>
                      <div class="user-element-symbol"> {{element.symbol}} </div>
                      <div class="user-element-name"> {{element.name}} </div>
                      <div class="user-element-weight"> {{element.weight}} </div>
                  </div>
                  <div class="user-element-description">
                        {{element.description}}
                     <span class="user-element-description-attribution"> -- Wikipedia </span>
                  </div>
             </div>
         </td>
      </ng-container>


      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let element; columns: displayedColumns;"
                    class="user-element-row"
                    [class.user-expanded-row]="expandedElement === element"
                    (click)="expandedElement = expandedElement === element ? null : element">
      </tr>
      <tr mat-row *matRowDef="let row; columns: ['expandedDetail']"></tr>
</table>

关于我应该如何处理这个问题或者是否有更好的方法来实现这种功能有什么想法吗?

想法是您的“数据源”有一个表单。例如,您创建一个像

这样的函数
createForm(data:any)
  {
    return new FormGroup({
      name:new FormControl(data.name),
      weight:new FormControl(data.weight),
      symbol:new FormControl(data.symbol),
      position:new FormControl(data.position),
    })
  }

你的数据就是

dataSource = ELEMENT_DATA.map(x=>({...x,form:this.createForm(x)}));

在您的可扩展行中添加表单和两个按钮“确定”“取消”

    <form [formGroup]="element.form">
      <input formControlName="name"/>
      <button (click)="element.name=element.form.value.name;
                       expandedElement=null">ok</button>
      <button (click)="element.form.patchValue(element);
                       expandedElement=null">cancel</button>
    </form>

你可以在stackblitz

中看到

注意:另一个管理选项是“就地编辑”,如

Update关于注释,我们可以将ELEMENT_DATA转换成FormArray

dataSource = new FormArray(ELEMENT_DATA.map(x=>this.createForm(x)));

然后我们得到了一个辅助函数return索引

处的formGroup
  getGroup(index:number)
  {
    return this.dataSource.at(index) as FormGroup
  }

如果使用最后一个,例如getGroup(i).get('position') 获取控件并用作数据源 dataSource.controls

<table mat-table
   [dataSource]="dataSource.controls" multiTemplateDataRows
   class="mat-elevation-z8">
<ng-container matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay">
    <th mat-header-cell *matHeaderCellDef> {{column}} </th>
    <1--see that we use let i=datIndex becaouse is a multiTemplateDataRows-->
    <td mat-cell *matCellDef="let element;let i=dataIndex"> {{getGroup(i).get(column).value}} </td>
  </ng-container>
....
<table>

在可扩展行中:

<form [formGroup]="getGroup(i)">
  <input formControlName="name"/>
</form>

嗯,唯一的是我们没有“确定”和“取消”按钮,当更改输入时,您会看到数据如何自动更改

看到一个new stackblitz