有没有办法在Angular材料中使用mat-table编辑表格的特定列 [英] Is there any way to edit specific Column of table using mat-table in Angular material

查看:27
本文介绍了有没有办法在Angular材料中使用mat-table编辑表格的特定列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<块引用>

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

<代码>><ng-container matColumnDef="weight">><th mat-h​​eader-cell *matHeaderCellDef>重量><td mat-cell *matCellDef="let element">{{element.weight}} </td>></ng-容器>><ng-container matColumnDef="symbol">><th mat-h​​eader-cell *matHeaderCellDef>符号><td mat-cell *matCellDef="let element">{{element.symbol}} </td>></ng-容器>>>><tr mat-h​​eader-row *matHeaderRowDef="displayedColumns"></tr>><tr mat-row *matRowDef="let row; columns:displayedColumns;"></tr>

<小时><块引用>

我是如何实现的:

<tr *ngFor="让数据源的数据"><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文件:

导出类 AppComponent {showEditTable = 假;editRowId: 任何 = '';选择行;displayColumns: string[] = ['position', 'name', 'weight', 'symbol'];数据源 = ELEMENT_DATA;editTableRow(val) {console.log('点击事件开始 val = ' + val);this.editRowId = val;console.log('click 事件以 val = ' + val 结束);}}

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

解决方案

纳曼,是一样的,你需要使用 来避免创建额外的标签,所以你的列变得像

 <ng-container matColumnDef="weight"><th mat-h​​eader-cell *matHeaderCellDef>重量<td mat-cell *matCellDef="let element"><ng-container *ngIf="element.position!==editRowId"><span (click)="edit(element.position,'weigth')">{{element.weight}} </span></ng-容器><ng-container *ngIf="element.position===editRowId"><input matInput name="weigth" [(ngModel)]="element.weight"></ng-容器></td></ng-容器>

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

我们声明了一个 MatInputs 的 ViewChildren

 @ViewChildren(MatInput,{read:ElementRef}) 输入:QueryList;

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

 编辑(行,元素){this.editRowId=row;setTimeout(()=>{this.inputs.find(x=>x.nativeElement.getAttribute('name')==element).nativeElement.focus()})}

您可以在stackblitz<中查看完整示例/a>

好吧,在示例中,数据是硬编码的.让我们想象一下数据(和结构)来自服务数据.数据很容易想象,因为它是相同的.我们可以将结构"想象为具有三个属性的对象数组:名称、头部和固定.如果fixed 为true,我们只显示数据,否则我们可以编辑.所以我们唯一需要的是在 *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},]

我们的桌子变得像

<ng-container *ngFor="let 模式列;let last=last"><ng-container [matColumnDef]="column.name"><th mat-h​​eader-cell *matHeaderCellDef>{{column.head}} </th><td mat-cell *matCellDef="let element"><ng-container *ngIf="element[schema[0].name]!==editRowId || column.fixed"><跨度(点击)="column.fixed?editRowId=-1:编辑(元素[架构[0].名称],列.名称)">{{元素[列名]}}</span></ng-容器><ng-container *ngIf="element[schema[0].name]===editRowId && !column.fixed"><input matInput [id]="column.name"[(ngModel)]="元素[column.name]"(blur)="last?editRowId=-1:null"></ng-容器></td></ng-容器></ng-容器><tr mat-h​​eader-row *matHeaderRowDef="displayedColumns"></tr><tr mat-row *matRowDef="let row; columns:displayedColumns;"></tr>

看到我们用 element[column[0].name]替换"element.position -我假设模式的第一个元素将是键"以及我们如何使用 [(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=数据;this.displayedColumns=schema.map(x=>x.name)this.schema=schema})}

displayColumns 必须是一个包含列名的数组,但我们也需要将模式"存储在一个数组中.

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

In my project i am using Angular Material's table for displaying value in table format, As per new requirement i have to perform in-line editing for last 2 column over other along with that if user click 1st column the other column get highlighted automatically and everything has to be done using Angular material

This is the last 2 column i want to perform in-line editing

>  <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>


How i achieved is as follows :

<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 file for above code :

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);
  }
}

I expect the result as table where last 2 column can be edited inline and at the same time i can send modified data to backend

解决方案

Naman, it's the same, you need use <ng-container>to avoid create extra tags, so your columns becomes like

  <!-- 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>

Well, I call to function "edit" passign two arguments, the position and a string indicate the "name" of the input attributes. This allow us "focus" the input clicked. how?

We declare a ViewChildren of the MatInputs

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

See that we get not the MatInput else the "ElementRef". This allow us, in out function edit get the element with the attributes name equal the string that pass as argument, and focus it. See that we need "enclosed" all in a setTimeout to allow Angular to show the input

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

You can see the full example in stackblitz

Well, in the example the data is hardcoded. Let's go to imagine that the data (and the structure) comes from a service data. The data is easy imagine because it's the same. The "structure" we can imagine as an array of object with three properties: name,head ad fixed. if fixed is true, we only show the data, else we can edit. So the only thing we need is create the columns in a *ngFor

First we are going to see how our schema can be defined. It's only an array

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

]

Our table becomes like

<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>

See that we "replace" element.position by element[column[0].name] -I supouse the first element of the schema will be the "key" and how we using [(ngModel)]="elemen[column.name]". Yes, to refererd to element.position we can refered too as elemen["position"] and remember we are iterating over "schema"

Another thing is that we are going to use "id", not "name". this is because if we using name, really Angular put as attrib some like: ng-reflect-name, and this don't allow us focus the input.

Finally we are get the data in the ngOnInit. We are going to use forkJoin to get together the schema and the data. A forkJoin only call and array of observables (in this case this.dataService.getSchema() and this.dataServide.getData, and return in an array the response of all the observables. We use the way ([variable1,variable2]) to store in "variable1" the first result and in variable2 the second result

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

The displayedColumns must be an array with the names of the columns, but we need to store in an array the "schema" too.

In the stackblitz I create a service and "simulate" the observable using the rxjs creation operator of, in a real application the data becomes from a httpClient.get(....)

这篇关于有没有办法在Angular材料中使用mat-table编辑表格的特定列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆