有啥方法可以在 Angular 材料中使用 mat-table 编辑特定的表格列

Posted

技术标签:

【中文标题】有啥方法可以在 Angular 材料中使用 mat-table 编辑特定的表格列【英文标题】:Is there any way to edit specific Column of table using mat-table in Angular material有什么方法可以在 Angular 材料中使用 mat-table 编辑特定的表格列 【发布时间】:2019-12-22 17:57:30 【问题描述】:

在我的项目中,我使用 Angular Material 的表格以表格格式显示值,根据新要求,如果用户单击另一列,我必须对最后 2 列执行在线编辑列会自动突出显示,一切都必须使用 Angular 材料完成

这是我要执行内联编辑的最后 2 列

>  <ng-container matColumnDef="weight">
>       <th mat-header-cell *matHeaderCellDef> Weight </th>
>       <td mat-cell *matCellDef="let element"> element.weight </td>
>     </ng-container>
>     <ng-container matColumnDef="symbol">
>       <th mat-header-cell *matHeaderCellDef> Symbol </th>
>       <td mat-cell *matCellDef="let element"> element.symbol </td>
>     </ng-container>
>   
>     
>     <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
>     <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>   </table>

我的实现方式如下:

<tbody>
                <tr *ngFor="let data of dataSource">      
                   <td >data.position</td>
                   <td >data.name</td>
                   <td *ngIf="data.position === editRowId"> <input matInput [(ngModel)]="data.weight"></td>
                   <td *ngIf="data.position !== editRowId" (click)="editTableRow(data.position)">data.weight</td>
                   <td *ngIf="data.position === editRowId"> <input matInput [(ngModel)]="data.symbol"></td>
                   <td *ngIf="data.position !== editRowId" (click)="editTableRow(data.position)">data.symbol</td>
                </tr>
            </tbody>

上述代码的 TS 文件:

export class AppComponent 
  showEditTable = false;
  editRowId: any = '';
  selectedRow;
  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = ELEMENT_DATA;
  editTableRow(val) 
  console.log('click event started val = ' + val);
  this.editRowId = val;
  console.log('click event ended with val = ' + val);
  

我希望结果是可以内联编辑最后 2 列的表格,同时我可以将修改后的数据发送到后端

【问题讨论】:

“数据”中没有值吗? 使用简单的 td tr 获取数据时没有问题,我可以填充值但不能使用 mat 表 对不起我的评论(我读得太快了你的问题)。在 mat-table 中是相似的,只是与 ng-container “玩”,看我的回答 【参考方案1】:

Naman,也是一样,你需要使用&lt;ng-container&gt;来避免创建额外的标签,所以你的列变得像

  <!-- Weight Column -->
  <ng-container matColumnDef="weight">
    <th mat-header-cell *matHeaderCellDef> Weight </th>
    <td mat-cell *matCellDef="let element"> 
      <ng-container *ngIf="element.position!==editRowId">
      <span (click)="edit(element.position,'weigth')">element.weight </span>
      </ng-container>
      <ng-container *ngIf="element.position===editRowId">
      <input matInput name="weigth" [(ngModel)]="element.weight"> 
      </ng-container>
      </td>
  </ng-container>

好吧,我调用函数“edit”传递两个参数,位置和字符串表示输入属性的“名称”。这允许我们“聚焦”点击的输入。怎么样?

我们声明 MatInputs 的 ViewChildren

  @ViewChildren(MatInput,read:ElementRef) inputs:QueryList<ElementRef>;

请注意,我们得到的不是 MatInput,而是“ElementRef”。这允许我们在 out 函数编辑中获取属性名称等于作为参数传递的字符串的元素,并将其聚焦。看到我们需要在 setTimeout 中“封闭”所有内容以允许 Angular 显示输入

  edit(row,element)
  
    this.editRowId=row;
    setTimeout(()=>
      this.inputs.find(x=>x.nativeElement.getAttribute('name')==element)
          .nativeElement.focus()
    )
  

你可以在stackblitz看到完整的例子

好吧,在示例中,数据是硬编码的。让我们假设数据(和结构)来自服务数据。数据很容易想象,因为它是相同的。我们可以将“结构”想象为具有三个属性的对象数组:名称、头部和固定。如果固定为真,我们只显示数据,否则我们可以编辑。所以我们唯一需要的是在 *ngFor 中创建列

首先,我们将了解如何定义我们的架构。这只是一个数组

[
   name:'position',head:"No.",fixed:true,
   name:'name',head:"Name",fixed:true,
   name:'weight',head:"Weigth",fixed:false,
   name:'symbol',head:"Symbol",fixed:false,

]

我们的桌子变成这样

<table #table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
    <ng-container *ngFor="let column of schema;let last=last">
        <ng-container [matColumnDef]="column.name">
            <th mat-header-cell *matHeaderCellDef> column.head </th>
            <td mat-cell *matCellDef="let element">
                <ng-container *ngIf="element[schema[0].name]!==editRowId || column.fixed">
                    <span 
                      (click)="column.fixed?editRowId=-1:
                               edit(element[schema[0].name],column.name)">
                         element[column.name] 
                    </span>
      </ng-container>
      <ng-container *ngIf="element[schema[0].name]===editRowId && !column.fixed">
         <input matInput [id]="column.name"
              [(ngModel)]="element[column.name]"
              (blur)="last?editRowId=-1:null"> 
      </ng-container>
      </td>
    </ng-container>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

看到我们用 element[column[0].name] “替换” element.position - 我想模式的第一个元素将是“key”以及我们如何使用 [(ngModel)]="elemen[列名]”。是的,要引用 element.position 我们也可以引用为 elemen["position"] 并记住我们正在迭代 "schema"

另一件事是我们将使用“id”,而不是“name”。这是因为如果我们使用名称,实际上 Angular 会将一些属性设置为:ng-reflect-name,这不允许我们关注输入。

最后我们得到了ngOnInit中的数据。我们将使用 forkJoin 将模式和数据放在一起。一个 forkJoin 只调用和数组 observables(在本例中为 this.dataService.getSchema() 和 this.dataServide.getData,并在一个数组中返回所有 observables 的响应。我们使用的方式 ([variable1,variable2]) 将第一个结果存储在“variable1”中,将第二个结果存储在 variable2 中

ngOnInit()

  forkJoin([this.dataService.getSchema(),this.dataService.getData()])
    .subscribe(([schema,data])=>
      this.dataSource=data;
      this.displayedColumns=schema.map(x=>x.name)
      this.schema=schema
    )

displayedColumns 必须是包含列名的数组,但我们也需要将“模式”存储在数组中。

在stackblitz 中,我创建了一个服务并使用 rxjs 创建运算符of “模拟”了 observable,在实际应用程序中,数据来自 httpClient.get(....)

【讨论】:

你真的救了我的命@Eliseo,非常感谢你帮助我摆脱了这种头痛。 如果列标签和值来自支持而不是硬编码怎么办? 我更新了我的答案。您需要考虑如何获得表的“模式”。我想象一个想法是一个对象数组,其中包含名称、头部和“固定”属性,指示我们一个字段是否可编辑,但你可以考虑另一个 Eliseo 请根据我更新的查询给我一些建议 column?toTitleCase(column.attributeName):null​​eader-cell> element[column.attributeName] ​​eader-row>

以上是关于有啥方法可以在 Angular 材料中使用 mat-table 编辑特定的表格列的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2+ 材料 mat-chip-list formArray 验证

使用 mat-tab-group 以编程方式在 Angular 2 材料中选择 mat-tab

Angular 材料 11:具有外观轮廓的 mat-form-field 以在整个项目中具有自定义的边界半径

Angular - 材料表,是不是可以通过单击按钮来编辑行?

如何在角度材料 2 中使用 mat-chip 和自动完成来保存选定的对象

Angular 材料:反应性与模板?