Динамическая загрузка столбцов и данных в таблицу в Angular 2

У меня есть HTML-страница, на которой я хочу создать таблицу. Столбцы в этой таблице являются динамическими, что означает, что они выбираются с сервера в переменную в компоненте, используяany[] тип. Данные в этой таблице также являются динамическими, что означает, что во время программирования я не знаю, какие столбцы и данные попадут в таблицу.

Я попробовал приведенный ниже код, но он, похоже, не работает и не дает никаких ошибок. Это просто создает пустойtd вtbody.

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

 Amit Kumar Ghosh12 дек. 2016 г., 14:53
Вы можете опубликовать окончательную HTML-разметку?
 user72863013 дек. 2016 г., 03:35
Обновленное единственное изменение, которое я сделал в размещенной разметке.

Ответы на вопрос(6)

Решение Вопроса

Вместо того, чтобы использовать

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

Вы должны использовать

<tr *ngFor="#data of data" *ngModel="data[column]">
 user72863007 авг. 2016 г., 07:37
Нет, это тоже не работает.
 bluePearl10 июл. 2018 г., 17:20
Когда я попробовал предложенный ответ, я получил бы ошибку сборки, потому что у меня есть и * ngFor, и * ngModel на одной строке. Как должен выглядеть объект json, чтобы это работало?
 user72863008 авг. 2016 г., 13:18
Это сработало. Большое спасибо !!
 dxpkumar22 февр. 2019 г., 10:06
Не могли бы вы опубликовать рабочую копию этого, поскольку я также сталкиваюсь с той же проблемой, и она не работает для меня. Ниже мой код.
 Lucas Tétreault08 авг. 2016 г., 04:40
О, я только что понял ... data.column на самом деле ничего не значит, потому что столбец - это, вероятно, строка или что-то, а не значение в данных. Попробуйте: <tr * ngFor = "# data of data" * ngModel = "data [column]">

Вот мое решение для 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] }} вместо использования<input> Отметьте, если вы не хотите, чтобы ваши поля были доступны для редактирования.

Это для тех, кто не хочет стол

Модель заголовка:

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>

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

чтобы передать столбец и строки в виде массива в компонент таблицы данных, он отображает только те столбцы и строки, которые я хочу видеть:

в компоненте:

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

Угловой 2 или Угловой 5, Мы должны создать компонент, чтобы его можно было использовать в любое время с любыми данными. Я проверил это и работает.

Файл :динамические-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);
  }

}

Файл :динамико-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>

Для реализации этого компонента вызовите в некоторый файл представления

Файл :вид-table.component.html

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

Файл :вид-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) { }
}

Ваш ответ на вопрос