Table

A table displays rows of data.

When To Use#

  • To display a collection of structured data.
  • To sort, search, paginate, filter data.

Import this Component Individually#

You can get more detail here.

import { NzTableModule } from 'ng-zorro-antd/table';

How To Use#

The Table component is both easy to use and highly customizable.

Highly Customizable#

You can use nz-table like W3C Standard <table> , developers can control every part of the table as you wish.

Component Enhancements#

The component in nz-table such as th, td, thead, etc are enhanced, developers can make the table sortable, filterable, fixed header, server rendering, etc easily with api provided.

Data Processing#

The data passed to [nzData] will be export with Template Context after processing, developers can use *ngFor to render current page data in table.

<nz-table #basicTable [nzData]="dataSet">
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
      <th>Address</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let data of basicTable.data">
      <td>{{data.name}}</td>
      <td>{{data.age}}</td>
      <td>{{data.address}}</td>
      <td>
        <a>Action 一 {{data.name}}</a>
        <nz-divider nzType="vertical"></nz-divider>
        <a>Delete</a>
      </td>
    </tr>
  </tbody>
</nz-table>

Examples

Name
Age
Address
Action
John Brown32New York No. 1 Lake ParkAction 一 John BrownDelete
Jim Green42London No. 1 Lake ParkAction 一 Jim GreenDelete
Joe Black32Sidney No. 1 Lake ParkAction 一 Joe BlackDelete

Simple table with actions.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-basic',
  template: `
    <nz-table #basicTable [nzData]="listOfData">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of basicTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
          <td>
            <a>Action 一 {{ data.name }}</a>
            <nz-divider nzType="vertical"></nz-divider>
            <a>Delete</a>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableBasicComponent {
  listOfData = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];
}
Name
Age
Address
Edward King 032London, Park Lane no. 0
Edward King 132London, Park Lane no. 1
Edward King 232London, Park Lane no. 2
Edward King 332London, Park Lane no. 3
Edward King 432London, Park Lane no. 4
Edward King 532London, Park Lane no. 5
Edward King 632London, Park Lane no. 6
Edward King 732London, Park Lane no. 7
Edward King 832London, Park Lane no. 8
Edward King 932London, Park Lane no. 9

Rows can be selectable by making first column as a selectable column, to perform operations and clear selections after selecting some rows, all data strategy should be controlled by the developers.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

export interface Data {
  id: number;
  name: string;
  age: number;
  address: string;
  disabled: boolean;
}

@Component({
  selector: 'nz-demo-table-row-selection-and-operation',
  template: `
    <div class="operate">
      <button
        nz-button
        [disabled]="numberOfChecked === 0"
        [nzType]="'primary'"
        [nzLoading]="isOperating"
        (click)="operateData()"
      >
        Reload
      </button>
      <span *ngIf="numberOfChecked">Selected {{ numberOfChecked }} items</span>
    </div>
    <nz-table
      #rowSelectionTable
      nzShowPagination
      nzShowSizeChanger
      [nzData]="listOfAllData"
      (nzCurrentPageDataChange)="currentPageDataChange($event)"
    >
      <thead>
        <tr>
          <th
            nzShowCheckbox
            [(nzChecked)]="isAllDisplayDataChecked"
            [nzIndeterminate]="isIndeterminate"
            (nzCheckedChange)="checkAll($event)"
          ></th>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of rowSelectionTable.data">
          <td
            nzShowCheckbox
            [(nzChecked)]="mapOfCheckedId[data.id]"
            [nzDisabled]="data.disabled"
            (nzCheckedChange)="refreshStatus()"
          ></td>
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      .operate {
        margin-bottom: 16px;
      }

      .operate span {
        margin-left: 8px;
      }
    `
  ]
})
export class NzDemoTableRowSelectionAndOperationComponent implements OnInit {
  isAllDisplayDataChecked = false;
  isOperating = false;
  isIndeterminate = false;
  listOfDisplayData: Data[] = [];
  listOfAllData: Data[] = [];
  mapOfCheckedId: { [key: string]: boolean } = {};
  numberOfChecked = 0;

  currentPageDataChange($event: Data[]): void {
    this.listOfDisplayData = $event;
    this.refreshStatus();
  }

  refreshStatus(): void {
    this.isAllDisplayDataChecked = this.listOfDisplayData
      .filter(item => !item.disabled)
      .every(item => this.mapOfCheckedId[item.id]);
    this.isIndeterminate =
      this.listOfDisplayData.filter(item => !item.disabled).some(item => this.mapOfCheckedId[item.id]) &&
      !this.isAllDisplayDataChecked;
    this.numberOfChecked = this.listOfAllData.filter(item => this.mapOfCheckedId[item.id]).length;
  }

  checkAll(value: boolean): void {
    this.listOfDisplayData.filter(item => !item.disabled).forEach(item => (this.mapOfCheckedId[item.id] = value));
    this.refreshStatus();
  }

  operateData(): void {
    this.isOperating = true;
    setTimeout(() => {
      this.listOfAllData.forEach(item => (this.mapOfCheckedId[item.id] = false));
      this.refreshStatus();
      this.isOperating = false;
    }, 1000);
  }

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfAllData.push({
        id: i,
        name: `Edward King ${i}`,
        age: 32,
        address: `London, Park Lane no. ${i}`,
        disabled: i % 2 === 0
      });
    }
  }
}
Name
Age
Address
Edward King 032London, Park Lane no. 0
Edward King 132London, Park Lane no. 1
Edward King 232London, Park Lane no. 2
Edward King 332London, Park Lane no. 3
Edward King 432London, Park Lane no. 4
Edward King 532London, Park Lane no. 5
Edward King 632London, Park Lane no. 6
Edward King 732London, Park Lane no. 7
Edward King 832London, Park Lane no. 8
Edward King 932London, Park Lane no. 9

Use nzShowRowSelection and nzSelections to custom selections.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'nz-demo-table-row-selection-custom',
  template: `
    <nz-table
      #rowSelectionTable
      nzShowSizeChanger
      [nzData]="listOfAllData"
      (nzCurrentPageDataChange)="currentPageDataChange($event)"
    >
      <thead>
        <tr>
          <th
            nzShowCheckbox
            nzShowRowSelection
            [nzSelections]="listOfSelection"
            [(nzChecked)]="isAllDisplayDataChecked"
            [nzIndeterminate]="isIndeterminate"
            (nzCheckedChange)="checkAll($event)"
          ></th>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of rowSelectionTable.data">
          <td nzShowCheckbox [(nzChecked)]="mapOfCheckedId[data.id]" (nzCheckedChange)="refreshStatus()"></td>
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableRowSelectionCustomComponent implements OnInit {
  listOfSelection = [
    {
      text: 'Select All Row',
      onSelect: () => {
        this.checkAll(true);
      }
    },
    {
      text: 'Select Odd Row',
      onSelect: () => {
        this.listOfDisplayData.forEach((data, index) => (this.mapOfCheckedId[data.id] = index % 2 !== 0));
        this.refreshStatus();
      }
    },
    {
      text: 'Select Even Row',
      onSelect: () => {
        this.listOfDisplayData.forEach((data, index) => (this.mapOfCheckedId[data.id] = index % 2 === 0));
        this.refreshStatus();
      }
    }
  ];
  isAllDisplayDataChecked = false;
  isIndeterminate = false;
  listOfDisplayData: any[] = [];
  listOfAllData: any[] = [];
  mapOfCheckedId: { [key: string]: boolean } = {};

  currentPageDataChange($event: Array<{ id: number; name: string; age: number; address: string }>): void {
    this.listOfDisplayData = $event;
    this.refreshStatus();
  }

  refreshStatus(): void {
    this.isAllDisplayDataChecked = this.listOfDisplayData.every(item => this.mapOfCheckedId[item.id]);
    this.isIndeterminate =
      this.listOfDisplayData.some(item => this.mapOfCheckedId[item.id]) && !this.isAllDisplayDataChecked;
  }

  checkAll(value: boolean): void {
    this.listOfDisplayData.forEach(item => (this.mapOfCheckedId[item.id] = value));
    this.refreshStatus();
  }

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfAllData.push({
        id: i,
        name: `Edward King ${i}`,
        age: 32,
        address: `London, Park Lane no. ${i}`
      });
    }
  }
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park
Jim Red32London No. 2 Lake Park

Use nzShowFilter of th to show filter menu, nzFilters to define options of the filter menu, nzFilterChange to get current selected filter option, and nzFilterMultiple to indicate whether it's multiple or single selection.

Use nzShowSort of th to make table sortable . nzSortKey to define sort key of column, use nzSortChange of thead to watch sort change, and nzSingleSort to indicate whether it is single column sort.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-head',
  template: `
    <nz-table #filterTable [nzData]="listOfDisplayData">
      <thead (nzSortChange)="sort($event)" nzSingleSort>
        <tr>
          <th
            nzShowSort
            nzSortKey="name"
            nzShowFilter
            [nzFilters]="listOfName"
            (nzFilterChange)="filter($event, searchAddress)"
          >
            Name
          </th>
          <th nzShowSort nzSortKey="age">Age</th>
          <th
            nzShowSort
            nzSortKey="address"
            nzShowFilter
            [nzFilterMultiple]="false"
            [nzFilters]="listOfAddress"
            (nzFilterChange)="filter(listOfSearchName, $event)"
          >
            Address
          </th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of filterTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableHeadComponent {
  sortName: string | null = null;
  sortValue: string | null = null;
  searchAddress: string;
  listOfName = [{ text: 'Joe', value: 'Joe' }, { text: 'Jim', value: 'Jim' }];
  listOfAddress = [{ text: 'London', value: 'London' }, { text: 'Sidney', value: 'Sidney' }];
  listOfSearchName: string[] = [];
  listOfData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [
    {
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      name: 'Jim Red',
      age: 32,
      address: 'London No. 2 Lake Park'
    }
  ];
  listOfDisplayData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [
    ...this.listOfData
  ];

  sort(sort: { key: string; value: string }): void {
    this.sortName = sort.key;
    this.sortValue = sort.value;
    this.search();
  }

  filter(listOfSearchName: string[], searchAddress: string): void {
    this.listOfSearchName = listOfSearchName;
    this.searchAddress = searchAddress;
    this.search();
  }

  search(): void {
    /** filter data **/
    const filterFunc = (item: { name: string; age: number; address: string }) =>
      (this.searchAddress ? item.address.indexOf(this.searchAddress) !== -1 : true) &&
      (this.listOfSearchName.length ? this.listOfSearchName.some(name => item.name.indexOf(name) !== -1) : true);
    const data = this.listOfData.filter(item => filterFunc(item));
    /** sort data **/
    if (this.sortName && this.sortValue) {
      this.listOfDisplayData = data.sort((a, b) =>
        this.sortValue === 'ascend'
          ? a[this.sortName!] > b[this.sortName!]
            ? 1
            : -1
          : b[this.sortName!] > a[this.sortName!]
          ? 1
          : -1
      );
    } else {
      this.listOfDisplayData = data;
    }
  }
}
Name
Age
Address
empty

No Data

you can enable a filter by default by setting a filter object's property: { byDefault: true }. Be aware that you should set the filtered table contents by yourself. In order to keep clarity and consistency of data, components would not do default filtering for you. Please refer to the demo.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-default-filter',
  template: `
    <nz-table #filterTable [nzData]="listOfDisplayData">
      <thead (nzSortChange)="sort($event)" nzSingleSort>
        <tr>
          <th
            nzShowSort
            nzSortKey="name"
            nzShowFilter
            [nzFilters]="listOfName"
            (nzFilterChange)="filter($event, searchAddress)"
          >
            Name
          </th>
          <th nzShowSort nzSortKey="age">Age</th>
          <th
            nzShowSort
            nzSortKey="address"
            nzShowFilter
            [nzFilterMultiple]="false"
            [nzFilters]="listOfAddress"
            (nzFilterChange)="filter(listOfSearchName, $event)"
          >
            Address
          </th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of filterTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableDefaultFilterComponent {
  listOfName = [{ text: 'Joe', value: 'Joe', byDefault: true }, { text: 'Jim', value: 'Jim' }];
  listOfAddress = [{ text: 'London', value: 'London', byDefault: true }, { text: 'Sidney', value: 'Sidney' }];
  listOfSearchName = ['Joe']; // You need to change it as well!
  sortName: string | null = null;
  sortValue: string | null = null;
  searchAddress = 'London';
  listOfData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [
    {
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      name: 'Jim Red',
      age: 32,
      address: 'London No. 2 Lake Park'
    }
  ];
  // You need to change it as well!
  listOfDisplayData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [];

  sort(sort: { key: string; value: string }): void {
    this.sortName = sort.key;
    this.sortValue = sort.value;
    this.search();
  }

  filter(listOfSearchName: string[], searchAddress: string): void {
    console.log(listOfSearchName, searchAddress);
    this.listOfSearchName = listOfSearchName;
    this.searchAddress = searchAddress;
    this.search();
  }

  search(): void {
    /** filter data **/
    const filterFunc = (item: { name: string; age: number; address: string }) =>
      (this.searchAddress ? item.address.indexOf(this.searchAddress) !== -1 : true) &&
      (this.listOfSearchName.length ? this.listOfSearchName.some(name => item.name.indexOf(name) !== -1) : true);
    const data = this.listOfData.filter(item => filterFunc(item));
    /** sort data **/
    if (this.sortName && this.sortValue) {
      this.listOfDisplayData = data.sort((a, b) =>
        this.sortValue === 'ascend'
          ? a[this.sortName!] > b[this.sortName!]
            ? 1
            : -1
          : b[this.sortName!] > a[this.sortName!]
          ? 1
          : -1
      );
    } else {
      this.listOfDisplayData = data;
    }
  }
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park
Jim Red32London No. 2 Lake Park

Control sorters by nzSort and nzSortChange on th.

  1. Defining nzSort of th means that it is in the controlled mode.
  2. Use nzSort to define current sort order.
  3. Use nzSortChange to watch the change of sort order.
  4. Can not used with nzSortChange or nzSingleSort of thead.
expand codeexpand code
import { Component } from '@angular/core';

interface Data {
  name: string;
  age: number;
  address: string;

  [key: string]: any;
}

@Component({
  selector: 'nz-demo-table-reset-filter',
  template: `
    <div class="table-operations">
      <button nz-button (click)="sort('age', 'descend')">Sort age</button>
      <button nz-button (click)="resetFilters()">Clear filters</button>
      <button nz-button (click)="resetSortAndFilters()">Clear filters and sorters</button>
    </div>
    <nz-table #filterTable [nzData]="listOfDisplayData">
      <thead>
        <tr>
          <th
            nzShowSort
            nzShowFilter
            [(nzSort)]="mapOfSort.name"
            (nzSortChange)="sort('name', $event)"
            [nzFilters]="listOfFilterName"
            (nzFilterChange)="search($event, listOfSearchAddress)"
          >
            Name
          </th>
          <th nzShowSort [(nzSort)]="mapOfSort.age" (nzSortChange)="sort('age', $event)">Age</th>
          <th
            nzShowSort
            nzShowFilter
            [(nzSort)]="mapOfSort.address"
            (nzSortChange)="sort('address', $event)"
            [nzFilters]="listOfFilterAddress"
            (nzFilterChange)="search(listOfSearchName, $event)"
          >
            Address
          </th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of filterTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      .table-operations {
        margin-bottom: 16px;
      }

      .table-operations > button {
        margin-right: 8px;
      }
    `
  ]
})
export class NzDemoTableResetFilterComponent {
  listOfSearchName: string[] = [];
  listOfSearchAddress: string[] = [];
  listOfFilterName = [{ text: 'Joe', value: 'Joe' }, { text: 'Jim', value: 'Jim' }];
  listOfFilterAddress = [{ text: 'London', value: 'London' }, { text: 'Sidney', value: 'Sidney' }];
  listOfData: Data[] = [
    {
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      name: 'Jim Red',
      age: 32,
      address: 'London No. 2 Lake Park'
    }
  ];
  listOfDisplayData = [...this.listOfData];
  mapOfSort: { [key: string]: any } = {
    name: null,
    age: null,
    address: null
  };
  sortName: string | null = null;
  sortValue: string | null = null;

  sort(sortName: string, value: string): void {
    this.sortName = sortName;
    this.sortValue = value;
    for (const key in this.mapOfSort) {
      this.mapOfSort[key] = key === sortName ? value : null;
    }
    this.search(this.listOfSearchName, this.listOfSearchAddress);
  }

  search(listOfSearchName: string[], listOfSearchAddress: string[]): void {
    this.listOfSearchName = listOfSearchName;
    this.listOfSearchAddress = listOfSearchAddress;
    const filterFunc = (item: Data) =>
      (this.listOfSearchAddress.length
        ? this.listOfSearchAddress.some(address => item.address.indexOf(address) !== -1)
        : true) &&
      (this.listOfSearchName.length ? this.listOfSearchName.some(name => item.name.indexOf(name) !== -1) : true);
    const listOfData = this.listOfData.filter((item: Data) => filterFunc(item));
    if (this.sortName && this.sortValue) {
      this.listOfDisplayData = listOfData.sort((a, b) =>
        this.sortValue === 'ascend'
          ? a[this.sortName!] > b[this.sortName!]
            ? 1
            : -1
          : b[this.sortName!] > a[this.sortName!]
          ? 1
          : -1
      );
    } else {
      this.listOfDisplayData = listOfData;
    }
  }

  resetFilters(): void {
    this.listOfFilterName = [{ text: 'Joe', value: 'Joe' }, { text: 'Jim', value: 'Jim' }];
    this.listOfFilterAddress = [{ text: 'London', value: 'London' }, { text: 'Sidney', value: 'Sidney' }];
    this.listOfSearchName = [];
    this.listOfSearchAddress = [];
    this.search(this.listOfSearchName, this.listOfSearchAddress);
  }

  resetSortAndFilters(): void {
    this.sortName = null;
    this.sortValue = null;
    this.mapOfSort = {
      name: null,
      age: null,
      address: null
    };
    this.resetFilters();
    this.search(this.listOfSearchName, this.listOfSearchAddress);
  }
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park
Jim Red32London No. 2 Lake Park

Implement a customized column search example via nz-dropdown, nzFilters and nzFilterChange.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-custom-filter-panel',
  template: `
    <nz-table #nzTable [nzData]="listOfDisplayData">
      <thead>
        <tr>
          <th nzCustomFilter>
            Name
            <i
              class="ant-table-filter-icon"
              nz-icon
              nz-dropdown
              #dropdown="nzDropdown"
              nzType="search"
              [nzDropdownMenu]="menu"
              [class.ant-table-filter-open]="dropdown.nzVisible"
              nzTrigger="click"
              nzPlacement="bottomRight"
              [nzClickHide]="false"
              nzTableFilter
            ></i>
          </th>
          <th>Age</th>
          <th nzShowFilter [nzFilters]="listOfFilterAddress" (nzFilterChange)="filterAddressChange($event)">Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of nzTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
    <nz-dropdown-menu #menu="nzDropdownMenu">
      <div class="search-box">
        <input type="text" nz-input placeholder="Search name" [(ngModel)]="searchValue" />
        <button nz-button nzSize="small" nzType="primary" (click)="search()" class="search-button">
          Search
        </button>
        <button nz-button nzSize="small" (click)="reset()">Reset</button>
      </div>
    </nz-dropdown-menu>
  `,
  styles: [
    `
      .search-box {
        padding: 8px;
      }

      .search-box input {
        width: 188px;
        margin-bottom: 8px;
        display: block;
      }

      .search-box button {
        width: 90px;
      }

      .search-button {
        margin-right: 8px;
      }
    `
  ]
})
export class NzDemoTableCustomFilterPanelComponent {
  searchValue = '';
  sortName: string | null = null;
  sortValue: string | null = null;
  listOfFilterAddress = [{ text: 'London', value: 'London' }, { text: 'Sidney', value: 'Sidney' }];
  listOfSearchAddress: string[] = [];
  listOfData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [
    {
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      name: 'Jim Red',
      age: 32,
      address: 'London No. 2 Lake Park'
    }
  ];
  listOfDisplayData = [...this.listOfData];

  reset(): void {
    this.searchValue = '';
    this.search();
  }

  sort(sortName: string, value: string): void {
    this.sortName = sortName;
    this.sortValue = value;
    this.search();
  }

  filterAddressChange(value: string[]): void {
    this.listOfSearchAddress = value;
    this.search();
  }

  search(): void {
    const filterFunc = (item: { name: string; age: number; address: string }) => {
      return (
        (this.listOfSearchAddress.length
          ? this.listOfSearchAddress.some(address => item.address.indexOf(address) !== -1)
          : true) && item.name.indexOf(this.searchValue) !== -1
      );
    };
    const data = this.listOfData.filter((item: { name: string; age: number; address: string }) => filterFunc(item));
    this.listOfDisplayData = data.sort((a, b) =>
      this.sortValue === 'ascend'
        ? a[this.sortName!] > b[this.sortName!]
          ? 1
          : -1
        : b[this.sortName!] > a[this.sortName!]
        ? 1
        : -1
    );
  }
}
Name
Gender
Email

This example shows how to fetch and present data from remote server, and how to implement filtering and sorting in server side by sending related parameters to server.

Note, this example use Mock API that you can look up in Network Console.

expand codeexpand code
import { HttpClient, HttpParams } from '@angular/common/http';
import { Component, Injectable, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable()
export class RandomUserService {
  randomUserUrl = 'https://api.randomuser.me/';

  getUsers(
    pageIndex: number = 1,
    pageSize: number = 10,
    sortField: string,
    sortOrder: string,
    genders: string[]
  ): Observable<{}> {
    let params = new HttpParams()
      .append('page', `${pageIndex}`)
      .append('results', `${pageSize}`)
      .append('sortField', sortField)
      .append('sortOrder', sortOrder);
    genders.forEach(gender => {
      params = params.append('gender', gender);
    });
    return this.http.get(`${this.randomUserUrl}`, {
      params
    });
  }

  constructor(private http: HttpClient) {}
}

@Component({
  selector: 'nz-demo-table-ajax',
  providers: [RandomUserService],
  template: `
    <nz-table
      #ajaxTable
      nzShowSizeChanger
      [nzFrontPagination]="false"
      [nzData]="listOfData"
      [nzLoading]="loading"
      [nzTotal]="total"
      [(nzPageIndex)]="pageIndex"
      [(nzPageSize)]="pageSize"
      (nzPageIndexChange)="searchData()"
      (nzPageSizeChange)="searchData(true)"
    >
      <thead (nzSortChange)="sort($event)" nzSingleSort>
        <tr>
          <th nzShowSort nzSortKey="name">Name</th>
          <th nzShowFilter [nzFilters]="filterGender" (nzFilterChange)="updateFilter($event)">Gender</th>
          <th nzShowSort nzSortKey="email"><span>Email</span></th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of ajaxTable.data">
          <td>{{ data.name.first }} {{ data.name.last }}</td>
          <td>{{ data.gender }}</td>
          <td>{{ data.email }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableAjaxComponent implements OnInit {
  pageIndex = 1;
  pageSize = 10;
  total = 1;
  listOfData = [];
  loading = true;
  sortValue: string | null = null;
  sortKey: string | null = null;
  filterGender = [{ text: 'male', value: 'male' }, { text: 'female', value: 'female' }];
  searchGenderList: string[] = [];

  sort(sort: { key: string; value: string }): void {
    this.sortKey = sort.key;
    this.sortValue = sort.value;
    this.searchData();
  }

  constructor(private randomUserService: RandomUserService) {}

  searchData(reset: boolean = false): void {
    if (reset) {
      this.pageIndex = 1;
    }
    this.loading = true;
    this.randomUserService
      .getUsers(this.pageIndex, this.pageSize, this.sortKey!, this.sortValue!, this.searchGenderList)
      .subscribe((data: any) => {
        this.loading = false;
        this.total = 200;
        this.listOfData = data.results;
      });
  }

  updateFilter(value: string[]): void {
    this.searchGenderList = value;
    this.searchData(true);
  }

  ngOnInit(): void {
    this.searchData();
  }
}

Middle size table

Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

Small size table

Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

Two compacted table size: middle and small, small size is used in Modal only.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-size',
  template: `
    <h4>Middle size table</h4>
    <nz-table #middleTable nzSize="middle" [nzData]="data">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of middleTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
    <h4>Small size table</h4>
    <nz-table #smallTable nzSize="small" [nzData]="data">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of smallTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      h4 {
        margin-bottom: 16px;
      }
    `
  ]
})
export class NzDemoTableSizeComponent {
  data = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];
}
Header
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

Add border, title and footer for table.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-bordered',
  template: `
    <nz-table #borderedTable nzBordered nzFooter="Footer" nzTitle="Header" [nzData]="dataSet">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of borderedTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableBorderedComponent {
  dataSet = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

When there's too much information to show and the table can't display all at once.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-expand',
  template: `
    <nz-table #nzTable [nzData]="listOfData">
      <thead>
        <tr>
          <th nzShowExpand></th>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <ng-template ngFor let-data [ngForOf]="nzTable.data">
          <tr>
            <td nzShowExpand [(nzExpand)]="mapOfExpandData[data.id]"></td>
            <td>{{ data.name }}</td>
            <td>{{ data.age }}</td>
            <td>{{ data.address }}</td>
          </tr>
          <tr [nzExpand]="mapOfExpandData[data.id]">
            <td></td>
            <td colspan="3">{{ data.description }}</td>
          </tr>
        </ng-template>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableExpandComponent {
  mapOfExpandData: { [key: string]: boolean } = {};
  listOfData = [
    {
      id: 1,
      name: 'John Brown',
      age: 32,
      expand: false,
      address: 'New York No. 1 Lake Park',
      description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.'
    },
    {
      id: 2,
      name: 'Jim Green',
      age: 42,
      expand: false,
      address: 'London No. 1 Lake Park',
      description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
    },
    {
      id: 3,
      name: 'Joe Black',
      age: 32,
      expand: false,
      address: 'Sidney No. 1 Lake Park',
      description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.'
    }
  ];
}
Name
Age
Home phone
Address
John Brown320571-2209890918889898989New York No. 1 Lake Park
Jim Green420571-2209833318889898888London No. 1 Lake Park
Joe Black320575-2209890918900010002Sidney No. 1 Lake Park
Jim Red1818900010002London No. 2 Lake Park
Jake White18

Use colspan and rowspan like W3C standards <table>

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-colspan-rowspan',
  template: `
    <nz-table #colSpanTable [nzData]="listOfData" nzBordered>
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th colspan="2">Home phone</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of colSpanTable.data; index as i">
          <td>{{ data.name }}</td>
          <td [attr.colspan]="i === 4 ? 5 : 1">{{ data.age }}</td>
          <td [attr.rowspan]="i === 2 ? 2 : 1" *ngIf="i !== 3 && i !== 4">{{ data.tel }}</td>
          <td *ngIf="i !== 4">{{ data.phone }}</td>
          <td *ngIf="i !== 4">{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableColspanRowspanComponent {
  listOfData = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      tel: '0571-22098909',
      phone: 18889898989,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      tel: '0571-22098333',
      phone: 18889898888,
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      tel: '0575-22098909',
      phone: 18900010002,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      key: '4',
      name: 'Jim Red',
      age: 18,
      tel: '0575-22098909',
      phone: 18900010002,
      address: 'London No. 2 Lake Park'
    },
    {
      key: '5',
      name: 'Jake White',
      age: 18,
      tel: '0575-22098909',
      phone: 18900010002,
      address: 'Dublin No. 2 Lake Park'
    }
  ];
}
Name
Age
Address
John Brown sr. 60New York No. 1 Lake Park
Joe Black 32Sidney No. 1 Lake Park

Display tree structure data in Table, control the indent width by setting nzIndentSize.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

export interface TreeNodeInterface {
  key: number;
  name: string;
  age: number;
  level: number;
  expand: boolean;
  address: string;
  children?: TreeNodeInterface[];
}

@Component({
  selector: 'nz-demo-table-expand-children',
  template: `
    <nz-table #expandTable [nzData]="listOfMapData">
      <thead>
        <tr>
          <th nzWidth="40%">Name</th>
          <th nzWidth="30%">Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <ng-container *ngFor="let data of expandTable.data">
          <ng-container *ngFor="let item of mapOfExpandedData[data.key]">
            <tr *ngIf="(item.parent && item.parent.expand) || !item.parent">
              <td
                [nzIndentSize]="item.level * 20"
                [nzShowExpand]="!!item.children"
                [(nzExpand)]="item.expand"
                (nzExpandChange)="collapse(mapOfExpandedData[data.key], item, $event)"
              >
                {{ item.name }}
              </td>
              <td>{{ item.age }}</td>
              <td>{{ item.address }}</td>
            </tr>
          </ng-container>
        </ng-container>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableExpandChildrenComponent implements OnInit {
  listOfMapData = [
    {
      key: 1,
      name: 'John Brown sr.',
      age: 60,
      address: 'New York No. 1 Lake Park',
      children: [
        {
          key: 11,
          name: 'John Brown',
          age: 42,
          address: 'New York No. 2 Lake Park'
        },
        {
          key: 12,
          name: 'John Brown jr.',
          age: 30,
          address: 'New York No. 3 Lake Park',
          children: [
            {
              key: 121,
              name: 'Jimmy Brown',
              age: 16,
              address: 'New York No. 3 Lake Park'
            }
          ]
        },
        {
          key: 13,
          name: 'Jim Green sr.',
          age: 72,
          address: 'London No. 1 Lake Park',
          children: [
            {
              key: 131,
              name: 'Jim Green',
              age: 42,
              address: 'London No. 2 Lake Park',
              children: [
                {
                  key: 1311,
                  name: 'Jim Green jr.',
                  age: 25,
                  address: 'London No. 3 Lake Park'
                },
                {
                  key: 1312,
                  name: 'Jimmy Green sr.',
                  age: 18,
                  address: 'London No. 4 Lake Park'
                }
              ]
            }
          ]
        }
      ]
    },
    {
      key: 2,
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];
  mapOfExpandedData: { [key: string]: TreeNodeInterface[] } = {};

  collapse(array: TreeNodeInterface[], data: TreeNodeInterface, $event: boolean): void {
    if ($event === false) {
      if (data.children) {
        data.children.forEach(d => {
          const target = array.find(a => a.key === d.key)!;
          target.expand = false;
          this.collapse(array, target, false);
        });
      } else {
        return;
      }
    }
  }

  convertTreeToList(root: object): TreeNodeInterface[] {
    const stack: any[] = [];
    const array: any[] = [];
    const hashMap = {};
    stack.push({ ...root, level: 0, expand: false });

    while (stack.length !== 0) {
      const node = stack.pop();
      this.visitNode(node, hashMap, array);
      if (node.children) {
        for (let i = node.children.length - 1; i >= 0; i--) {
          stack.push({ ...node.children[i], level: node.level + 1, expand: false, parent: node });
        }
      }
    }

    return array;
  }

  visitNode(node: TreeNodeInterface, hashMap: { [key: string]: any }, array: TreeNodeInterface[]): void {
    if (!hashMap[node.key]) {
      hashMap[node.key] = true;
      array.push(node);
    }
  }

  ngOnInit(): void {
    this.listOfMapData.forEach(item => {
      this.mapOfExpandedData[item.key] = this.convertTreeToList(item);
    });
  }
}
Name
Age
Address
Edward King 032London, Park Lane no. 0
Edward King 132London, Park Lane no. 1
Edward King 232London, Park Lane no. 2
Edward King 332London, Park Lane no. 3
Edward King 432London, Park Lane no. 4
Edward King 532London, Park Lane no. 5
Edward King 632London, Park Lane no. 6
Edward King 732London, Park Lane no. 7
Edward King 832London, Park Lane no. 8
Edward King 932London, Park Lane no. 9
Edward King 1032London, Park Lane no. 10
Edward King 1132London, Park Lane no. 11
Edward King 1232London, Park Lane no. 12
Edward King 1332London, Park Lane no. 13
Edward King 1432London, Park Lane no. 14
Edward King 1532London, Park Lane no. 15
Edward King 1632London, Park Lane no. 16
Edward King 1732London, Park Lane no. 17
Edward King 1832London, Park Lane no. 18
Edward King 1932London, Park Lane no. 19
Edward King 2032London, Park Lane no. 20
Edward King 2132London, Park Lane no. 21
Edward King 2232London, Park Lane no. 22
Edward King 2332London, Park Lane no. 23
Edward King 2432London, Park Lane no. 24
Edward King 2532London, Park Lane no. 25
Edward King 2632London, Park Lane no. 26
Edward King 2732London, Park Lane no. 27
Edward King 2832London, Park Lane no. 28
Edward King 2932London, Park Lane no. 29
Edward King 3032London, Park Lane no. 30
Edward King 3132London, Park Lane no. 31
Edward King 3232London, Park Lane no. 32
Edward King 3332London, Park Lane no. 33
Edward King 3432London, Park Lane no. 34
Edward King 3532London, Park Lane no. 35
Edward King 3632London, Park Lane no. 36
Edward King 3732London, Park Lane no. 37
Edward King 3832London, Park Lane no. 38
Edward King 3932London, Park Lane no. 39
Edward King 4032London, Park Lane no. 40
Edward King 4132London, Park Lane no. 41
Edward King 4232London, Park Lane no. 42
Edward King 4332London, Park Lane no. 43
Edward King 4432London, Park Lane no. 44
Edward King 4532London, Park Lane no. 45
Edward King 4632London, Park Lane no. 46
Edward King 4732London, Park Lane no. 47
Edward King 4832London, Park Lane no. 48
Edward King 4932London, Park Lane no. 49

Display large amounts of data in scrollable view.

Specify the width of each th if header and cell do not align properly.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'nz-demo-table-fixed-header',
  template: `
    <nz-table #headerTable [nzData]="listOfData" [nzPageSize]="50" [nzScroll]="{ y: '240px' }">
      <thead>
        <tr>
          <th nzWidth="150px">Name</th>
          <th nzWidth="150px">Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of headerTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableFixedHeaderComponent implements OnInit {
  listOfData: any[] = [];

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfData.push({
        name: `Edward King ${i}`,
        age: 32,
        address: `London, Park Lane no. ${i}`
      });
    }
  }
}
Full Name
Age
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Action
John Brown32New YorkNew YorkNew YorkNew YorkNew YorkNew YorkNew YorkNew Yorkaction
Jim Green40LondonLondonLondonLondonLondonLondonLondonLondonaction

To fix some columns and scroll inside other columns, and you must set nzScroll.x, nzLeft and nzRight meanwhile.

We use sticky property to fixed column,browsers support.

Specify the width of th if header and cell do not align properly.

A fixed value which is greater than table width for nzScroll.x is recommended. The sum of unfixed columns should not greater than nzScroll.x.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-fixed-columns',
  template: `
    <nz-table #columnTable [nzData]="listOfData" [nzScroll]="{ x: '1100px' }">
      <thead>
        <tr>
          <th nzWidth="100px" nzLeft="0px">Full Name</th>
          <th nzWidth="100px" nzLeft="100px">Age</th>
          <th nzWidth="100px">Column 1</th>
          <th nzWidth="100px">Column 2</th>
          <th nzWidth="100px">Column 3</th>
          <th nzWidth="100px">Column 4</th>
          <th nzWidth="100px">Column 5</th>
          <th nzWidth="100px">Column 6</th>
          <th nzWidth="100px">Column 7</th>
          <th nzRight="100px" nzWidth="100px">Column 8</th>
          <th nzWidth="100px" nzRight="0px">Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of columnTable.data">
          <td nzLeft="0px">{{ data.name }}</td>
          <td nzLeft="100px">{{ data.age }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td nzRight="100px">{{ data.address }}</td>
          <td nzRight="0px">
            <a>action</a>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableFixedColumnsComponent {
  listOfData = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 40,
      address: 'London'
    }
  ];
}
Full Name
Age
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Action
Edward King 032LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 132LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 232LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 332LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 432LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 532LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 632LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 732LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 832LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 932LondonLondonLondonLondonLondonLondonLondonLondonaction

A Solution for displaying large amounts of data with long columns.

We use sticky property to fixed column,browsers support.

Specify the width of th if header and cell do not align properly.

A fixed value which is greater than table width for nzScroll.x is recommended. The sum of unfixed columns should not greater than nzScroll.x.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'nz-demo-table-fixed-columns-header',
  template: `
    <nz-table #fixedTable [nzData]="listOfData" [nzScroll]="{ x: '1150px', y: '240px' }">
      <thead>
        <tr>
          <th nzWidth="150px" nzLeft="0px">Full Name</th>
          <th nzWidth="100px" nzLeft="150px">Age</th>
          <th nzWidth="100px">Column 1</th>
          <th nzWidth="100px">Column 2</th>
          <th nzWidth="100px">Column 3</th>
          <th nzWidth="100px">Column 4</th>
          <th nzWidth="100px">Column 5</th>
          <th nzWidth="100px">Column 6</th>
          <th nzWidth="100px">Column 7</th>
          <th nzWidth="100px">Column 8</th>
          <th nzWidth="100px" nzRight="0px">Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of fixedTable.data">
          <td nzLeft="0px">{{ data.name }}</td>
          <td nzLeft="150px">{{ data.age }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td nzRight="0px">
            <a>action</a>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableFixedColumnsHeaderComponent implements OnInit {
  listOfData: any[] = [];

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfData.push({
        name: `Edward King ${i}`,
        age: 32,
        address: `London`
      });
    }
  }
}
Name
Other
Company
Gender
Age
Address
Company Address
Company Name
Street
Block
Building
Door No.
John Brown1Lake ParkC2035Lake Street 42SoftLake CoM
John Brown2Lake ParkC2035Lake Street 42SoftLake CoM
John Brown3Lake ParkC2035Lake Street 42SoftLake CoM
John Brown4Lake ParkC2035Lake Street 42SoftLake CoM
John Brown5Lake ParkC2035Lake Street 42SoftLake CoM
John Brown6Lake ParkC2035Lake Street 42SoftLake CoM
John Brown7Lake ParkC2035Lake Street 42SoftLake CoM
John Brown8Lake ParkC2035Lake Street 42SoftLake CoM
John Brown9Lake ParkC2035Lake Street 42SoftLake CoM
John Brown10Lake ParkC2035Lake Street 42SoftLake CoM

Group table head with nzWidthConfig.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'nz-demo-table-grouping-columns',
  template: `
    <nz-table
      #groupingTable
      [nzData]="listOfDisplayData"
      nzBordered
      nzSize="middle"
      [nzWidthConfig]="widthConfig"
      [nzScroll]="scrollConfig"
    >
      <thead>
        <tr>
          <th rowspan="4" nzLeft="0px" nzShowFilter [nzFilters]="filterName" (nzFilterChange)="search($event)">Name</th>
          <th colspan="4">Other</th>
          <th colspan="2">Company</th>
          <th rowspan="4" nzRight="0px">Gender</th>
        </tr>
        <tr>
          <th rowspan="3" nzShowSort [(nzSort)]="sortValue" (nzSortChange)="search(searchName)">Age</th>
          <th colspan="3">Address</th>
          <th rowspan="3">Company Address</th>
          <th rowspan="3">Company Name</th>
        </tr>
        <tr>
          <th rowspan="2">Street</th>
          <th colspan="2">Block</th>
        </tr>
        <tr>
          <th>Building</th>
          <th>Door No.</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of groupingTable.data">
          <td nzLeft="0px">{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.street }}</td>
          <td>{{ data.building }}</td>
          <td>{{ data.number }}</td>
          <td>{{ data.companyAddress }}</td>
          <td>{{ data.companyName }}</td>
          <td nzRight="0px">{{ data.gender }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableGroupingColumnsComponent implements OnInit {
  widthConfig = ['100px', '200px', '200px', '100px', '100px', '200px', '200px', '100px'];
  scrollConfig = { x: '1200px', y: '240px' };
  listOfDisplayData: any[] = [];
  listOfData: any[] = [];
  sortValue: string | null = null;
  filterName = [{ text: 'Joe', value: 'Joe' }, { text: 'John', value: 'John' }];
  searchName: string[] = [];

  search(searchName: string[]): void {
    this.searchName = searchName;
    const filterFunc = (item: any) => {
      return this.searchName.length ? this.searchName.some(name => item.name.indexOf(name) !== -1) : true;
    };
    const listOfData = this.listOfData.filter(item => filterFunc(item));
    this.listOfDisplayData = listOfData.sort((a, b) =>
      this.sortValue === 'ascend' ? (a.age > b.age ? 1 : -1) : b.age > a.age ? 1 : -1
    );
  }

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfData.push({
        name: 'John Brown',
        age: i + 1,
        street: 'Lake Park',
        building: 'C',
        number: 2035,
        companyAddress: 'Lake Street 42',
        companyName: 'SoftLake Co',
        gender: 'M'
      });
    }
    this.listOfDisplayData = [...this.listOfData];
  }
}
Name
Age
Address
Action
Edward King 0
32London, Park Lane no. 0Delete
Edward King 1
32London, Park Lane no. 1Delete

Table with editable cells.

expand codeexpand code
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
import { NzInputDirective } from 'ng-zorro-antd/input';

@Component({
  selector: 'nz-demo-table-edit-cell',
  template: `
    <button nz-button (click)="addRow()" nzType="primary">Add</button>
    <nz-table #editRowTable nzBordered [nzData]="listOfData">
      <thead>
        <tr>
          <th nzWidth="30%">Name</th>
          <th>Age</th>
          <th>Address</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of editRowTable.data" class="editable-row">
          <td>
            <div class="editable-cell" *ngIf="editId !== data.id; else editTpl">
              <div class="editable-cell-value-wrap" (click)="startEdit(data.id, $event)">
                {{ data.name }}
              </div>
            </div>
            <ng-template #editTpl>
              <input type="text" nz-input [(ngModel)]="data.name" />
            </ng-template>
          </td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
          <td>
            <a nz-popconfirm nzTitle="Sure to delete?" (nzOnConfirm)="deleteRow(data.id)">Delete</a>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      button {
        margin-bottom: 16px;
      }

      .editable-cell {
        position: relative;
      }

      .editable-cell-value-wrap {
        padding: 5px 12px;
        cursor: pointer;
      }

      .editable-row:hover .editable-cell-value-wrap {
        border: 1px solid #d9d9d9;
        border-radius: 4px;
        padding: 4px 11px;
      }
    `
  ]
})
export class NzDemoTableEditCellComponent implements OnInit {
  i = 0;
  editId: string | null;
  listOfData: any[] = [];
  @ViewChild(NzInputDirective, { static: false, read: ElementRef }) inputElement: ElementRef;

  @HostListener('window:click', ['$event'])
  handleClick(e: MouseEvent): void {
    if (this.editId && this.inputElement && this.inputElement.nativeElement !== e.target) {
      this.editId = null;
    }
  }

  addRow(): void {
    this.listOfData = [
      ...this.listOfData,
      {
        id: `${this.i}`,
        name: `Edward King ${this.i}`,
        age: '32',
        address: `London, Park Lane no. ${this.i}`
      }
    ];
    this.i++;
  }

  deleteRow(id: string): void {
    this.listOfData = this.listOfData.filter(d => d.id !== id);
  }

  startEdit(id: string, event: MouseEvent): void {
    event.preventDefault();
    event.stopPropagation();
    this.editId = id;
  }

  ngOnInit(): void {
    this.addRow();
    this.addRow();
  }
}
Name
Age
Address
Action
Edrward 0 32 London Park no. 0
Edrward 1 32 London Park no. 1
Edrward 2 32 London Park no. 2
Edrward 3 32 London Park no. 3
Edrward 4 32 London Park no. 4
Edrward 5 32 London Park no. 5
Edrward 6 32 London Park no. 6
Edrward 7 32 London Park no. 7
Edrward 8 32 London Park no. 8
Edrward 9 32 London Park no. 9

Table with editable rows.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'nz-demo-table-edit-row',
  template: `
    <nz-table #editRowTable nzBordered [nzData]="listOfData">
      <thead>
        <tr>
          <th nzWidth="25%">Name</th>
          <th nzWidth="15%">Age</th>
          <th nzWidth="40%">Address</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of editRowTable.data">
          <td>
            <ng-container *ngIf="!editCache[data.id].edit; else nameInputTpl">
              {{ data.name }}
            </ng-container>
            <ng-template #nameInputTpl>
              <input type="text" nz-input [(ngModel)]="editCache[data.id].data.name" />
            </ng-template>
          </td>
          <td>
            <ng-container *ngIf="!editCache[data.id].edit; else ageInputTpl">
              {{ data.age }}
            </ng-container>
            <ng-template #ageInputTpl>
              <input type="text" nz-input [(ngModel)]="editCache[data.id].data.age" />
            </ng-template>
          </td>
          <td>
            <ng-container *ngIf="!editCache[data.id].edit; else addressInputTpl">
              {{ data.address }}
            </ng-container>
            <ng-template #addressInputTpl>
              <input type="text" nz-input [(ngModel)]="editCache[data.id].data.address" />
            </ng-template>
          </td>
          <td>
            <div class="editable-row-operations">
              <ng-container *ngIf="!editCache[data.id].edit; else saveTpl">
                <a (click)="startEdit(data.id)">Edit</a>
              </ng-container>
              <ng-template #saveTpl>
                <a (click)="saveEdit(data.id)">Save</a>
                <a nz-popconfirm nzTitle="Sure to cancel?" (nzOnConfirm)="cancelEdit(data.id)">Cancel</a>
              </ng-template>
            </div>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      .editable-row-operations a {
        margin-right: 8px;
      }
    `
  ]
})
export class NzDemoTableEditRowComponent implements OnInit {
  editCache: { [key: string]: any } = {};
  listOfData: any[] = [];

  startEdit(id: string): void {
    this.editCache[id].edit = true;
  }

  cancelEdit(id: string): void {
    const index = this.listOfData.findIndex(item => item.id === id);
    this.editCache[id] = {
      data: { ...this.listOfData[index] },
      edit: false
    };
  }

  saveEdit(id: string): void {
    const index = this.listOfData.findIndex(item => item.id === id);
    Object.assign(this.listOfData[index], this.editCache[id].data);
    this.editCache[id].edit = false;
  }

  updateEditCache(): void {
    this.listOfData.forEach(item => {
      this.editCache[item.id] = {
        edit: false,
        data: { ...item }
      };
    });
  }

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfData.push({
        id: `${i}`,
        name: `Edrward ${i}`,
        age: 32,
        address: `London Park no. ${i}`
      });
    }
    this.updateEditCache();
  }
}
Name
Platform
Version
Upgraded
Creator
Date
Action
ScreemiOS10.3.4.5654500Jack2014-12-24 23:12:00Publish
ScreemiOS10.3.4.5654500Jack2014-12-24 23:12:00Publish
ScreemiOS10.3.4.5654500Jack2014-12-24 23:12:00Publish

Showing more detailed info of every row.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'nz-demo-table-nested-table',
  template: `
    <nz-table #nestedTable [nzData]="listOfParentData" [nzPageSize]="10">
      <thead>
        <tr>
          <th nzShowExpand></th>
          <th>Name</th>
          <th>Platform</th>
          <th>Version</th>
          <th>Upgraded</th>
          <th>Creator</th>
          <th>Date</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        <ng-template ngFor let-data [ngForOf]="nestedTable.data">
          <tr>
            <td nzShowExpand [(nzExpand)]="data.expand"></td>
            <td>{{ data.name }}</td>
            <td>{{ data.platform }}</td>
            <td>{{ data.version }}</td>
            <td>{{ data.upgradeNum }}</td>
            <td>{{ data.creator }}</td>
            <td>{{ data.createdAt }}</td>
            <td>
              <a>Publish</a>
            </td>
          </tr>
          <tr [nzExpand]="data.expand">
            <td></td>
            <td colspan="7">
              <nz-table #innerTable [nzData]="listOfChildrenData" nzSize="middle" [nzShowPagination]="false">
                <thead>
                  <tr>
                    <th>Date</th>
                    <th>Name</th>
                    <th>Status</th>
                    <th>Upgrade Status</th>
                    <th>Action</th>
                  </tr>
                </thead>
                <tbody>
                  <tr *ngFor="let data of innerTable.data">
                    <td>{{ data.date }}</td>
                    <td>{{ data.name }}</td>
                    <td>
                      <nz-badge [nzStatus]="'success'" [nzText]="'Finished'"></nz-badge>
                    </td>
                    <td>{{ data.upgradeNum }}</td>
                    <td>
                      <span class="table-operation">
                        <a nz-dropdown class="operation" [nzDropdownMenu]="menu">
                          Pause <i nz-icon nzType="down"></i>
                        </a>
                        <nz-dropdown-menu #menu="nzDropdownMenu">
                          <ul nz-menu>
                            <li nz-menu-item>
                              <a>Action 1</a>
                            </li>
                            <li nz-menu-item>
                              <a>Action 2</a>
                            </li>
                          </ul>
                        </nz-dropdown-menu>
                        <nz-divider nzType="vertical"></nz-divider>
                        <a class="operation">Stop</a>
                        <nz-divider nzType="vertical"></nz-divider>
                        <a>More</a>
                      </span>
                    </td>
                  </tr>
                </tbody>
              </nz-table>
            </td>
          </tr>
        </ng-template>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableNestedTableComponent implements OnInit {
  listOfParentData: any[] = [];
  listOfChildrenData: any[] = [];

  ngOnInit(): void {
    for (let i = 0; i < 3; ++i) {
      this.listOfParentData.push({
        key: i,
        name: 'Screem',
        platform: 'iOS',
        version: '10.3.4.5654',
        upgradeNum: 500,
        creator: 'Jack',
        createdAt: '2014-12-24 23:12:00',
        expand: false
      });
    }
    for (let i = 0; i < 3; ++i) {
      this.listOfChildrenData.push({
        key: i,
        date: '2014-12-24 23:12:00',
        name: 'This is production name',
        upgradeNum: 'Upgraded: 56'
      });
    }
  }
}


Full Name
Age
Index
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Action

Virtual scrolling combine with cdk scrolling used to display large data, you can get cdkVirtualScrollViewport in NzTableComponent and find more API here.

expand codeexpand code
import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { NzTableComponent } from 'ng-zorro-antd/table';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export interface VirtualDataInterface {
  index: number;
  name: string;
  age: number;
  address: string;
}

@Component({
  selector: 'nz-demo-table-virtual',
  template: `
    <button nz-button (click)="scrollToIndex(200)">Scroll To Index 200</button>
    <br />
    <br />
    <nz-table
      #virtualTable
      nzVirtualScroll
      [nzVirtualItemSize]="54"
      [nzData]="listOfData"
      [nzVirtualForTrackBy]="trackByIndex"
      [nzFrontPagination]="false"
      [nzShowPagination]="false"
      [nzScroll]="{ x: '1300px', y: '240px' }"
    >
      <thead>
        <tr>
          <th nzWidth="200px" nzLeft="0px">Full Name</th>
          <th nzWidth="100px" nzLeft="200px">Age</th>
          <th nzWidth="100px">Index</th>
          <th nzWidth="100px">Column 1</th>
          <th nzWidth="100px">Column 2</th>
          <th nzWidth="100px">Column 3</th>
          <th nzWidth="100px">Column 4</th>
          <th nzWidth="100px">Column 5</th>
          <th nzWidth="100px">Column 6</th>
          <th nzWidth="100px">Column 7</th>
          <th nzWidth="100px">Column 8</th>
          <th nzWidth="100px" nzRight="0px">Action</th>
        </tr>
      </thead>
      <tbody>
        <ng-template nz-virtual-scroll let-data let-index="index">
          <tr>
            <td nzLeft="0px">{{ data.name }} {{ index }}</td>
            <td nzLeft="200px">{{ data.age }}</td>
            <td>{{ data.index }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td nzRight="0px">
              <a>action</a>
            </td>
          </tr>
        </ng-template>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableVirtualComponent implements OnInit, AfterViewInit, OnDestroy {
  @ViewChild('virtualTable', { static: false }) nzTableComponent: NzTableComponent;
  private destroy$ = new Subject();
  listOfData: VirtualDataInterface[] = [];

  scrollToIndex(index: number): void {
    this.nzTableComponent.cdkVirtualScrollViewport.scrollToIndex(index);
  }

  trackByIndex(_: number, data: VirtualDataInterface): number {
    return data.index;
  }

  ngOnInit(): void {
    const data = [];
    for (let i = 0; i < 20000; i++) {
      data.push({
        index: i,
        name: `Edward King`,
        age: 32,
        address: `London`
      });
    }
    this.listOfData = data;
  }

  ngAfterViewInit(): void {
    this.nzTableComponent.cdkVirtualScrollViewport.scrolledIndexChange
      .pipe(takeUntil(this.destroy$))
      .subscribe((data: number) => {
        console.log('scroll index to', data);
      });
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

By using custom components, we can integrate table with cdk drag-drop to implement drag sorting.

expand codeexpand code
import { moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop';
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-drag-sorting',
  template: `
    <nz-table [nzData]="listOfData" [nzFrontPagination]="false" [nzShowPagination]="false">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody cdkDropList (cdkDropListDropped)="drop($event)">
        <tr *ngFor="let data of listOfData" cdkDrag>
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      ::ng-deep .cdk-drag-preview {
        display: table;
      }

      ::ng-deep .cdk-drag-placeholder {
        opacity: 0;
      }
    `
  ]
})
export class NzDemoTableDragSortingComponent {
  listOfData = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];

  drop(event: CdkDragDrop<string[]>): void {
    moveItemInArray(this.listOfData, event.previousIndex, event.currentIndex);
  }
}
Company
Contact
Country
Alfreds FutterkisteMaria AndersGermany
Centro comercial MoctezumaFrancisco ChangMexico
Ernst HandelRoland MendelAustria
Island TradingHelen BennettUK
Laughing Bacchus WinecellarsYoshi TannamuriCanada
Magazzini Alimentari RiunitiGiovanni RovelliItaly

Template mode, same usage as table, there is no need to data to nzData.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-template',
  template: `
    <nz-table nzTemplateMode>
      <thead>
        <tr>
          <th>Company</th>
          <th>Contact</th>
          <th>Country</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Alfreds Futterkiste</td>
          <td>Maria Anders</td>
          <td>Germany</td>
        </tr>
        <tr>
          <td>Centro comercial Moctezuma</td>
          <td>Francisco Chang</td>
          <td>Mexico</td>
        </tr>
        <tr>
          <td>Ernst Handel</td>
          <td>Roland Mendel</td>
          <td>Austria</td>
        </tr>
        <tr>
          <td>Island Trading</td>
          <td>Helen Bennett</td>
          <td>UK</td>
        </tr>
        <tr>
          <td>Laughing Bacchus Winecellars</td>
          <td>Yoshi Tannamuri</td>
          <td>Canada</td>
        </tr>
        <tr>
          <td>Magazzini Alimentari Riuniti</td>
          <td>Giovanni Rovelli</td>
          <td>Italy</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableTemplateComponent {}
Here is Title
Name
Age
Address
Action
John Brown12New York No. 1 Lake ParkAction 一 John BrownDelete
John Brown22New York No. 2 Lake ParkAction 一 John BrownDelete
John Brown32New York No. 3 Lake ParkAction 一 John BrownDelete
John Brown42New York No. 4 Lake ParkAction 一 John BrownDelete
John Brown52New York No. 5 Lake ParkAction 一 John BrownDelete
John Brown62New York No. 6 Lake ParkAction 一 John BrownDelete
John Brown72New York No. 7 Lake ParkAction 一 John BrownDelete
John Brown82New York No. 8 Lake ParkAction 一 John BrownDelete
John Brown92New York No. 9 Lake ParkAction 一 John BrownDelete
John Brown102New York No. 10 Lake ParkAction 一 John BrownDelete

Select different settings to see the result.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'nz-demo-table-dynamic-settings',
  template: `
    <div class="components-table-demo-control-bar">
      <form nz-form nzLayout="inline">
        <nz-form-item>
          <nz-form-label><label>Bordered</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="bordered" name="bordered"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Loading</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="loading" name="loading"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Pagination</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="pagination" name="pagination"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>PageSizeChanger</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="sizeChanger" name="sizeChanger"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Title</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="title" name="title"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Column Header</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="header" name="header"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Footer</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="footer" name="footer"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Expandable</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="expandable" name="expandable"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Checkbox</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="checkbox" name="checkbox"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Fixed Header</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="fixHeader" name="fixHeader"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>No Result</label></nz-form-label>
          <nz-form-control
            ><nz-switch [(ngModel)]="noResult" (ngModelChange)="noResultChange($event)" name="noResult"></nz-switch
          ></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Simple Pagination</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="simple" name="simple"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Size</label></nz-form-label>
          <nz-form-control>
            <nz-radio-group [(ngModel)]="size" name="size">
              <label nz-radio-button nzValue="default">Default</label>
              <label nz-radio-button nzValue="middle">Middle</label>
              <label nz-radio-button nzValue="small">Small</label>
            </nz-radio-group>
          </nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Pagination Position</label></nz-form-label>
          <nz-form-control>
            <nz-radio-group [(ngModel)]="position" name="position">
              <label nz-radio-button nzValue="top">Top</label>
              <label nz-radio-button nzValue="bottom">Bottom</label>
              <label nz-radio-button nzValue="both">Both</label>
            </nz-radio-group>
          </nz-form-control>
        </nz-form-item>
      </form>
    </div>
    <nz-table
      #dynamicTable
      [nzScroll]="fixHeader ? { y: '240px' } : null"
      [nzData]="listOfData"
      [nzBordered]="bordered"
      [nzSimple]="simple"
      [nzLoading]="loading"
      [nzPaginationPosition]="position"
      [nzShowSizeChanger]="sizeChanger"
      [nzFrontPagination]="pagination"
      [nzShowPagination]="pagination"
      [nzFooter]="footer ? 'Here is Footer' : null"
      [nzTitle]="title ? 'Here is Title' : null"
      [nzSize]="size"
      (nzCurrentPageDataChange)="currentPageDataChange($event)"
    >
      <thead>
        <tr *ngIf="header">
          <th nzWidth="50px" nzShowExpand *ngIf="expandable"></th>
          <th
            nzWidth="62px"
            nzShowCheckbox
            *ngIf="checkbox"
            [(nzChecked)]="allChecked"
            [nzIndeterminate]="indeterminate"
            (nzCheckedChange)="checkAll($event)"
          ></th>
          <th nzWidth="150px">Name</th>
          <th nzWidth="70px">Age</th>
          <th>Address</th>
          <th nzWidth="260px">Action</th>
        </tr>
      </thead>
      <tbody>
        <ng-template ngFor let-data [ngForOf]="dynamicTable.data">
          <tr>
            <td nzShowExpand *ngIf="expandable" [(nzExpand)]="data.expand"></td>
            <td nzShowCheckbox *ngIf="checkbox" [(nzChecked)]="data.checked" (nzCheckedChange)="refreshStatus()"></td>
            <td>{{ data.name }}</td>
            <td>{{ data.age }}</td>
            <td>{{ data.address }}</td>
            <td>
              <a href="#">Action 一 {{ data.name }}</a>
              <nz-divider nzType="vertical"></nz-divider>
              <a href="#">Delete</a>
            </td>
          </tr>
          <tr [nzExpand]="data.expand && expandable">
            <td></td>
            <td [attr.colspan]="checkbox ? 5 : 4">{{ data.description }}</td>
          </tr>
        </ng-template>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      .components-table-demo-control-bar {
        margin-bottom: 12px;
      }

      .nz-form-item {
        margin-right: 16px;
        margin-bottom: 8px;
      }
    `
  ]
})
export class NzDemoTableDynamicSettingsComponent implements OnInit {
  listOfData: any[] = [];
  bordered = false;
  loading = false;
  sizeChanger = false;
  pagination = true;
  header = true;
  title = true;
  footer = true;
  fixHeader = false;
  size = 'small';
  expandable = true;
  checkbox = true;
  allChecked = false;
  indeterminate = false;
  displayData: any[] = [];
  simple = false;
  noResult = false;
  position = 'bottom';

  currentPageDataChange(
    $event: Array<{
      name: string;
      age: number;
      address: string;
      checked: boolean;
      expand: boolean;
      description: string;
    }>
  ): void {
    this.displayData = $event;
    this.refreshStatus();
  }

  refreshStatus(): void {
    const validData = this.displayData.filter(value => !value.disabled);
    const allChecked = validData.length > 0 && validData.every(value => value.checked === true);
    const allUnChecked = validData.every(value => !value.checked);
    this.allChecked = allChecked;
    this.indeterminate = !allChecked && !allUnChecked;
  }

  checkAll(value: boolean): void {
    this.displayData.forEach(data => {
      if (!data.disabled) {
        data.checked = value;
      }
    });
    this.refreshStatus();
  }

  ngOnInit(): void {
    for (let i = 1; i <= 100; i++) {
      this.listOfData.push({
        name: 'John Brown',
        age: `${i}2`,
        address: `New York No. ${i} Lake Park`,
        description: `My name is John Brown, I am ${i}2 years old, living in New York No. ${i} Lake Park.`,
        checked: false,
        expand: false
      });
    }
  }

  noResultChange(status: boolean): void {
    this.listOfData = [];
    if (!status) {
      this.ngOnInit();
    }
  }
}

API#

nz-table#

PropertyDescriptionTypeDefaultGlobal Config
[nzData]Data record array to be displayedany[]-
[nzFrontPagination]Whether paginate data in front side,should set to false if you want to paginate data in server side or display all data in tablebooleantrue
[nzTotal]Total data count, should set when nzServerRender is truenumber-
[nzPageIndex]pageIndex , double bindingnumber-
[nzPageSize]pageSize, double bindingnumber-
[nzShowPagination]Whether show pagination component in bottom of the tablebooleantrue
[nzPaginationPosition]Specify the position of Pagination'top' | 'bottom' | 'both'bottom
[nzBordered]Whether to show all table bordersbooleanfalse
[nzWidthConfig]Set col width can not used with nzWidth of thstring[]-
[nzSize]Size of table'middle' | 'small' | 'default''default'
[nzLoading]Loading status of tablebooleanfalse
[nzLoadingIndicator]the spinning indicatorTemplateRef<void>-
[nzLoadingDelay]Specifies a delay in milliseconds for loading state (prevent flush)number0
[nzScroll]Whether table can be scrolled in x/y direction, x or y can be a string that indicates the width and height of table bodyobject-
[nzTitle]Table title rendererstring | TemplateRef<void>-
[nzFooter]Table footer rendererstring | TemplateRef<void>-
[nzNoResult]Custom no result contentstring | TemplateRef<void>-
[nzPageSizeOptions]Specify the sizeChanger optionsnumber[][10, 20, 30, 40]
[nzShowQuickJumper]Determine whether you can jump to pages directlybooleanfalse
[nzShowSizeChanger]Determine whether nzPageSize can be changedbooleanfalse
[nzShowTotal]To display Pagination total number and range, same as PaginationTemplateRef<{ $implicit: number, range: [ number, number ] }>-
[nzItemRender]to customize Pagination item, same as PaginationTemplateRef<{ $implicit: 'page' | 'prev' | 'next', page: number }>-
[nzHideOnSinglePage]Whether to hide pager on single pagebooleanfalse
[nzSimple]whether to use simple modeboolean-
[nzTemplateMode]template mode,no need to pass data to nzDatabooleanfalse
[nzVirtualScroll]Enable virtual scroll mode,work with [nzScroll]booleanfalse
[nzVirtualItemSize]The size of the items in the list, same as cdk itemSizenumber0
[nzVirtualMaxBufferPx]The number of pixels worth of buffer to render for when rendering new items, same as cdk maxBufferPxnumber200
[nzVirtualMinBufferPx]The minimum amount of buffer rendered beyond the viewport (in pixels),same as cdk minBufferPxnumber100
[nzVirtualForTrackBy]The TrackByFunction to use for tracking changes.TrackByFunction<T>-
(nzPageIndexChange)pageIndex change callbackEventEmitter<number>-
(nzPageSizeChange)pageSize change callbackEventEmitter<number>-
(nzCurrentPageDataChange)current pageData change callbackEventEmitter<any[]>-

th#

Checkbox property

PropertyDescriptionTypeDefault
[nzShowCheckbox]Whether add nz-checkboxboolean-
[nzDisabled]Whether disable checkboxboolean-
[nzIndeterminate]Indeterminate statusboolean-
[nzChecked]Checked status, double bindingboolean-
(nzCheckedChange)Checked status change callbackEventEmitter<boolean>-

Selection property

PropertyDescriptionTypeDefault
[nzShowRowSelection]Whether show selectionsboolean-
[nzSelections]Selection options include text and onSelect functionArray<{ text: string, onSelect: any }>-

Filter property

PropertyDescriptionTypeDefault
[nzShowFilter]Whether show filterboolean-
[nzFilters]Filter options, text, and value for callback, byDefault to enable filter by defaultArray<{ text: string; value: any; byDefault?: boolean }>-
[nzFilterMultiple]Whether filter multiple modebooleantrue
(nzFilterChange)Filter change callback valueEventEmitter<any[] | any>-

Style property

PropertyDescriptionTypeDefault
[nzWidth]Specify the column width, can not used when grouping columnsstring-
[nzLeft]Left pixels, used to fixed column to leftstring-
[nzRight]Right pixels, used to fixed column to rightstring-
[nzAlign]Specify how content is aligned'left' | 'right' | 'center'-

Other property

PropertyDescriptionTypeDefault
[nzExpand]Whether current column include expand iconboolean-

td#

Checkbox property

PropertyDescriptionTypeDefault
[nzShowCheckbox]Whether add nz-checkboxboolean-
[nzDisabled]Whether disable checkboxboolean-
[nzIndeterminate]Indeterminate statusboolean-
[nzChecked]Checked status, double bindingboolean-
(nzCheckedChange)Checked status change callbackEventEmitter<boolean>-

Expand property

PropertyDescriptionTypeDefault
[nzShowExpand]Whether show expand iconboolean-
[nzExpand]Current expand status, double bindingboolean-
(nzExpandChange)Expand status change callbackEventEmitter<boolean>-

Style property

PropertyDescriptionTypeDefault
[nzLeft]Left pixels, used to fixed column to leftstring-
[nzRight]Right pixels, used to fixed column to rightstring-
[nzAlign]Specify how content is aligned'left' | 'right' | 'center'-

Other property

PropertyDescriptionTypeDefault
[nzIndentSize]Indent size in pixels of tree datanumber-

thead#

PropertyDescriptionTypeDefault
[nzSingleSort]Whether single column sort modebooleanfalse
(nzSortChange)sort change callback,should used with nzSortKey of thEventEmitter<{ nzSortKey: string, value: 'descend' | 'ascend' | null }>-

tr#

PropertyDescriptionTypeDefault
[nzExpand]Whether expand current row,used with nzExpand of tdboolean-

[nz-virtual-scroll]#

virtual scroll directive work with ng-template, type: TemplateRef<{ $implicit: any, index: number }>.

Note#

According to Angular documentation,developers should not use push or splice to change the data passed to nzData

    // add data
    this.dataSet = [ ...this.dataSet, {
      key    : `${this.i}`,
      name   : `Edward King ${this.i}`,
      age    : '32',
      address: `London, Park Lane no. ${this.i}`
    }];
    // remove data
    this.dataSet = this.dataSet.filter(d => d.key !== i);