【问题标题】:Dynamically loading columns and data in to table in Angular 2在Angular 2中将列和数据动态加载到表中
【发布时间】:2016-08-07 02:23:06
【问题描述】:

我有一个要在其中创建表格的 HTML 页面。此表中的列是动态的,这意味着它们是使用any[] 类型从服务器获取到组件中的变量中的。此表中的数据也是动态的,这意味着在编程时我不知道哪些列和数据会被绑定到表中。

我尝试了下面的代码,但它似乎不起作用或给出任何错误。它只是在tbody 中创建空的td

Expense.component.html

<div class="panel panel-default" style="margin-top:10px;">
<div class="panel-heading">
    Expenses
</div>
<div class="panel-body" style="position:relative">
    <div class="table-responsive">
        <table class="table">
            <thead>
                <tr>
                    <th *ngFor="#column of columns">
                        {{column}}
                    </th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor="#data of data">
                    <td *ngFor="#column of columns">
                        {{data.column}}
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

在上面的代码中,列已成功创建,但数据和列混搭不起作用。我确信 Angular 2 中一定有办法实现这一点。

Expense.component.ts

export class ExpenseComponent implements OnInit {
errorMessage: any[];
columns: string[];
data: any[];

constructor(private _commonService: CommonService, private _expenseService: ExpenseService) {

}

ngOnInit(): void {
    this._commonService.getColumnNames('condomanagement', 'expenses')
        .subscribe(data => this.promise(data), error => this.errorMessage = <any>error);
}

private promise(data: string[]) {
    this.columns = data;
    this._expenseService.getExpenses('condomanagement', this.columns)
        .subscribe(data => this.anotherPromise(data), error => this.errorMessage = <any>error);
}

private anotherPromise(data: any[]) {
    this.data = data;
    console.log(this.columns);
    console.log(this.data);
}

private handleError(error: Response) {
    console.error(error);
    return Observable.throw(error.json().error || 'Server error');
}
}

根据我的试验,数据正在上面的代码中登录到控制台,但在 HTML 中不起作用。请问有什么想法吗?

更新:刚刚使用了这样的插值,它工作了

{{mydata[column]}}

【问题讨论】:

  • 你能发布最终的 html 标记吗?
  • 更新的是我在发布的标记中所做的唯一更改。

标签: angular


【解决方案1】:

可用于Angular 2、5、6、7。我们应该创建一个组件,以便可以随时使用任何类型的数据。我已经对其进行了测试并且正在运行。

文件:dynamic-table.component.ts

import { Component, OnInit, Input, Output, OnChanges, SimpleChanges } from '@angular/core';

@Component({
  selector: 'dynamic-table',
  templateUrl: './dynamic-table.component.html',
  styleUrls: ['./dynamic-table.component.scss']
})
export class DynamicTableComponent implements OnInit, OnChanges {

  @Input() tableHeads: Array<String> = new Array<String>();
  @Input() tableDatas: Array<any> = new Array<any>();
  @Input() tableColName: Array<String> = new Array<String>();
  private tableColNameGenerated: Array<String> = new Array<String>();
  private isTableColNameSet: Boolean = false;

  constructor() { }

  ngOnInit() {

  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes['tableHeads']) {
      if (this.tableHeads.length > 0) {
        // console.log('tableHeads');
      }
    }

    if (changes['tableDatas']) {
      if (!this.isTableColNameSet) {
        if (this.tableDatas.length > 0) {
          this.tableColNameGenerated = this.getKeys(this.tableDatas[0]);
          if (!this.isHeadAndColLengthSame(this.tableHeads, this.tableColNameGenerated)) {
            console.error('Table column row is not same as with property name in self generated');
         }
        }
      }
    }

    if (changes['tableColName']) {
      if (this.tableColName.length > 0) {
        this.tableColNameGenerated = this.tableColName;
        this.isTableColNameSet = true;
        if (!this.isHeadAndColLengthSame(this.tableHeads, this.tableColName)) {
          console.error('Table column row is not same as with property name provided');
        }
      }
    }
  }

  /**
  * This method will fetch all the property name and convert it into a list of String.
  * @param {Array<String>} head Pass in the list of String, which contains table header values
  * @param {Array<String>} col Pass in the list of String, which contains column property 
  * name, which was received from Input or generated using this.getKeys()
  */
  private isHeadAndColLengthSame(head: Array<String>, col: Array<String>): Boolean {
    return (head.length === col.length);
  }

  /**
  * This method will fetch all the property name and convert it into a list of String.
  * @param {any} value Pass Instance of Object eg. new User()
  */
  private getKeys(value: any): Array<String> {
    return Object.keys(value);
  }

}

文件:dynamic-table.component.html

<table>
  <thead>
    <tr class="table-head">
      <th *ngFor="let tableHead of tableHeads">{{tableHead}}</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let tableData of tableDatas">
      <td *ngFor="let colName of tableColNameGenerated"> {{tableData[colName]}}</td>
    </tr>
  </tbody>
</table>

在某个视图文件中实现这个组件调用

文件:view-table.component.html

<div>
  <dynamic-table [tableHeads]="tableHead" 
                 [tableDatas]="userDetails" 
                 [tableColName]="tableColName">
  </dynamic-table>
</div>

文件:view-table.component.ts

export class ViewTable implements OnInit{

  // fetch or create an Object of UserDetails type and pass it to dynamic-table
  private userDetails: Array<UserDetails>;
  // required to provide the table header, you can call an api or hard code the column name.
  private tableHead: Array<String>;  
  // optional, you can hard code the property name or just send the data of an object and dynamic-table component will figure out.
  private tableColName: Array<String>;  

  constructor(){
      this.tableHead = new Array<String>('Name', 'Age', 'Gender');
      // this.tableColName = new Array<String>('name', 'age', 'gender');
      this.userDetails = new Array<UserDetails>();
  }
   ngOnInit() {
      this.userDetails.push(new UserDetails('Apple', 18, 'Male'));
      this.userDetails.push(new UserDetails('Banana', 24, 'Female'));
      this.userDetails.push(new UserDetails('Mango', 34, 'Male'));
      this.userDetails.push(new UserDetails('Orange', 13, 'Female'));
      this.userDetails.push(new UserDetails('Guava', 56, 'Male'));
   }
}

export class UserDetails{
    constructor(public name: String, public age: Number, public gender: String) { }
}

【讨论】:

    【解决方案2】:

    我对这个问题的解决方案是 在 Html 文件中编写此代码

    在 Ts 文件中编写这段代码

    <table>
    <thead>
      <th *ngFor="let item of header">
        {{item}}
      </th>
    </thead>
    <tbody>
      <tr *ngFor="let record of test">
        <td *ngFor="let key of header">
          {{record[key]}}
        </td>
      </tr>
    </tbody>
    

    【讨论】:

    • 请不要在回答中使用代码图片。取而代之的是edit 你的答案包括formatted text
    【解决方案3】:

    而不是使用

    <tr *ngFor="#data of data">
    

    你应该使用

    <tr *ngFor="#data of data" *ngModel="data[column]">
    

    【讨论】:

    • 哦,我刚刚意识到... data.column 并没有真正的意义,因为 column 可能是一个字符串或其他东西,而不是数据的值。试试:
    • 当我尝试建议的答案时,我会收到构建错误,因为我在同一行上同时拥有 *ngFor 和 *ngModel。 json 对象的外观如何才能使其正常工作?
    • 能否请您发布一份工作副本,因为我也面临同样的问题,它不适合我。下面是我的代码。
    【解决方案4】:

    在 Angular2 测试版中:

    grid.html

    <mat-table #table [dataSource]="dataSource">
      <ng-container [matColumnDef]="columnName" *ngFor="let columnName of displayedColumns">
        <mat-header-cell *matHeaderCellDef> {{columnName}} </mat-header-cell>
        <mat-cell *matCellDef="let element"> {{element[columnName]}} </mat-cell>
      </ng-container>
    
      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
      <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
    </mat-table>
    

    grid.ts

    export class GridDynamicComponent {
      rows = new Array<CorporateEmployee>();
      dataSource: any;
      displayedColumns = [];
      yourFunction(...) {
        rows = ... // Update your model
        this.displayedColumns = rows.length > 0 ? Object.keys(rows[0]) : [];
        this.dataSource = new MatTableDataSource(rows);
      }
    }
    

    【讨论】:

      【解决方案5】:

      我的解决方案是使用 Input() 将列和行作为数组提供给数据表组件,它只呈现我想要查看的列和行:

      在组件中:

        @Input('cols')
        set cols(value: string){
          this._cols = value;
        }
        get cols(){
          return this._cols;
        }
      
        Input('rows')
        set rows(value: string){
          this._rows = value;
        }
        get rows(){
          return this._rows;
        }
      

      在视图中:

      <app-data-table *ngIf="hotels"
                        [cols]="['Hotel Name','Status','Phone','Actions']"
                        [rows]="['HotelListTitle','HotelListSaleActive','HotelListPhone']"
                        [data]="hotels"
                        [excelData]="excelData"></app-data-table>
      

      【讨论】:

        【解决方案6】:

        这是我针对 Angular 5.x+ 的解决方案:

        <div class="table-responsive">
            <table class="table">
              <thead>
                <tr>
                  <th *ngFor="let cols of columnsData">{{ cols.displayName }}</th>
                </tr>
              </thead>
              <tbody>
                <tr *ngFor="let data of tableData" > 
                  <td *ngFor="let col of columnsData">
                    <input [(ngModel)]="data[col.name]" type="text" />
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        

        假设您将 columnsData 设置为 [{displayName: 'First Name', name: 'name'}, {displayName: 'Last Name', name: 'surname'}] 当然,您可以根据需要自定义它们。

        如果您的字段不可编辑,您可以只插入 {{ data[col.name] }} 而不是使用 &lt;input&gt; 标记。

        【讨论】:

          【解决方案7】:

          这是给那些不想吃桌子的人

          标头模型:

          public tempData: any[] = [{
            header: 'Import',
            field: 'import'
          }, {
            header: 'Receive:',
            field: 'receive'
          }, {
            header: 'Send',
            field: 'send'
          }],
          

          实际数据:

          public actaulData: any[] = [
          { send: 'send to data', import: 'import data', receive: 'receive data'}]
          

          查看:

          <section class="p-grid p-col-12 p-nogutter" *ngFor="let data of actaulData">
                <h6 class="p-col-4 border-right">
                  <div *ngFor="let item of tempData">
                    <p>
                      <strong>{{ item.header }}</strong>: {{ data[item.field] }}
                    </p>
                  </div>
                </h6>
          

          【讨论】:

            猜你喜欢
            相关资源
            最近更新 更多
            热门标签