igniteui-angular-grid-data-operations

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Ignite UI for Angular — Grid Data Operations & State Management

Ignite UI for Angular — 网格数据操作与状态管理

Description

说明

This skill teaches AI agents how to implement data manipulation patterns with Ignite UI for Angular grids. It covers cell editing, row editing, batch editing, sorting, filtering, grouping, paging, remote data binding, virtualization, and how to wire up services correctly.
When to use this skill vs. the Data Grids skill
SkillFocus
Data Grids (
igniteui-angular-grids
)
Grid structure — choosing a grid type, column configuration, templates, layout, selection, toolbar, export
Grid Data Operations (this skill)Data manipulation — editing (cell/row/batch), sorting, filtering, grouping, paging, remote data, state persistence
If the user's question is about what to render (columns, templates, grid type), use the Data Grids skill. If it's about how data flows (sorting, filtering, remote services, transactions), use this skill.
本技能指导AI代理如何使用Ignite UI for Angular网格实现数据操作模式,涵盖单元格编辑、行编辑、批量编辑、排序、筛选、分组、分页、远程数据绑定、虚拟化,以及如何正确配置服务。
何时使用本技能 vs 数据网格技能
技能核心关注点
数据网格 (
igniteui-angular-grids
)
网格结构——选择网格类型、列配置、模板、布局、选择、工具栏、导出
网格数据操作(本技能)数据操作——编辑(单元格/行/批量)、排序、筛选、分组、分页、远程数据、状态持久化
如果用户的问题是关于渲染内容(列、模板、网格类型),使用数据网格技能;如果是关于数据流转(排序、筛选、远程服务、事务),使用本技能。

Prerequisites

前置条件

  • Angular 20+ project
  • igniteui-angular
    installed, or
    @infragistics/igniteui-angular
    for licensed users — both packages share the same entry-point structure
  • A theme applied (see the Theming skill)
  • Familiarity with the Data Grids skill for grid setup basics
  • Angular 20+ 项目
  • 已安装
    igniteui-angular
    ,或授权用户安装
    @infragistics/igniteui-angular
    ——两个包的入口结构一致
  • 已应用主题(参考主题技能)
  • 熟悉数据网格技能的网格基础配置

Accessing the Grid Instance

获取网格实例

All programmatic data operations require a reference to the grid component. Use
viewChild
with the correct component type for your grid.
AGENT INSTRUCTION: Check
package.json
to determine whether the project uses
igniteui-angular
or
@infragistics/igniteui-angular
. Replace the package prefix in every import accordingly. Always use specific entry points — never the root barrel of either package.
typescript
import { Component, ChangeDetectionStrategy, signal, viewChild } from '@angular/core';

// Open-source package — import from specific entry points
// Grid Lite (separate npm package — requires `npm install igniteui-grid-lite`)
import { IgxGridLiteComponent } from 'igniteui-angular/grids/lite';
// Flat Grid
import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
// Tree Grid
import { IgxTreeGridComponent, IGX_TREE_GRID_DIRECTIVES } from 'igniteui-angular/grids/tree-grid';
// Hierarchical Grid
import { IgxHierarchicalGridComponent, IGX_HIERARCHICAL_GRID_DIRECTIVES } from 'igniteui-angular/grids/hierarchical-grid';
// Pivot Grid
import { IgxPivotGridComponent, IGX_PIVOT_GRID_DIRECTIVES } from 'igniteui-angular/grids/pivot-grid';

// Licensed package — same entry-point paths, different prefix:
// import { IgxGridComponent, IGX_GRID_DIRECTIVES } from '@infragistics/igniteui-angular/grids/grid';
// import { IgxTreeGridComponent, IGX_TREE_GRID_DIRECTIVES } from '@infragistics/igniteui-angular/grids/tree-grid';
// import { IgxHierarchicalGridComponent, IGX_HIERARCHICAL_GRID_DIRECTIVES } from '@infragistics/igniteui-angular/grids/hierarchical-grid';
// import { IgxPivotGridComponent, IGX_PIVOT_GRID_DIRECTIVES } from '@infragistics/igniteui-angular/grids/pivot-grid';

// AVOID — never import from the root barrel (wrong for BOTH variants)
// import { IgxGridComponent } from 'igniteui-angular';
// import { IgxGridComponent } from '@infragistics/igniteui-angular';
所有程序化数据操作都需要获取网格组件的引用。使用
viewChild
并为你的网格指定正确的组件类型
代理指令: 检查
package.json
以确定项目使用
igniteui-angular
还是
@infragistics/igniteui-angular
,并相应替换所有导入语句中的包前缀。始终使用特定入口点——绝不要使用任一包的根桶。
typescript
import { Component, ChangeDetectionStrategy, signal, viewChild } from '@angular/core';

// 开源包——从特定入口点导入
// Grid Lite(独立npm包——需要执行`npm install igniteui-grid-lite`)
import { IgxGridLiteComponent } from 'igniteui-angular/grids/lite';
// 普通网格
import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
// 树形网格
import { IgxTreeGridComponent, IGX_TREE_GRID_DIRECTIVES } from 'igniteui-angular/grids/tree-grid';
// 分层网格
import { IgxHierarchicalGridComponent, IGX_HIERARCHICAL_GRID_DIRECTIVES } from 'igniteui-angular/grids/hierarchical-grid';
// 透视网格
import { IgxPivotGridComponent, IGX_PIVOT_GRID_DIRECTIVES } from 'igniteui-angular/grids/pivot-grid';

// 授权包——入口路径相同,前缀不同:
// import { IgxGridComponent, IGX_GRID_DIRECTIVES } from '@infragistics/igniteui-angular/grids/grid';
// import { IgxTreeGridComponent, IGX_TREE_GRID_DIRECTIVES } from '@infragistics/igniteui-angular/grids/tree-grid';
// import { IgxHierarchicalGridComponent, IGX_HIERARCHICAL_GRID_DIRECTIVES } from '@infragistics/igniteui-angular/grids/hierarchical-grid';
// import { IgxPivotGridComponent, IGX_PIVOT_GRID_DIRECTIVES } from '@infragistics/igniteui-angular/grids/pivot-grid';

// 避免——绝不要从根桶导入(两个包都不允许)
// import { IgxGridComponent } from 'igniteui-angular';
// import { IgxGridComponent } from '@infragistics/igniteui-angular';

Flat Grid Example

普通网格示例

typescript
@Component({
  selector: 'app-orders-grid',
  imports: [IGX_GRID_DIRECTIVES],
  templateUrl: './orders-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class OrdersGridComponent {
  gridRef = viewChild.required<IgxGridComponent>('grid');
  protected data = signal<Order[]>([]);

  sortByName() {
    this.gridRef().sort({ fieldName: 'name', dir: SortingDirection.Asc, ignoreCase: true });
  }
}
typescript
@Component({
  selector: 'app-orders-grid',
  imports: [IGX_GRID_DIRECTIVES],
  templateUrl: './orders-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class OrdersGridComponent {
  gridRef = viewChild.required<IgxGridComponent>('grid');
  protected data = signal<Order[]>([]);

  sortByName() {
    this.gridRef().sort({ fieldName: 'name', dir: SortingDirection.Asc, ignoreCase: true });
  }
}

Tree Grid Example

树形网格示例

typescript
@Component({
  selector: 'app-org-tree',
  imports: [IGX_TREE_GRID_DIRECTIVES],
  templateUrl: './org-tree.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class OrgTreeComponent {
  // Use IgxTreeGridComponent for tree grids
  treeGridRef = viewChild.required<IgxTreeGridComponent>('treeGrid');
  protected employees = signal<Employee[]>([]);
}
html
<igx-tree-grid #treeGrid
  [data]="employees()"
  primaryKey="id"
  foreignKey="managerId"
  height="600px">
  <igx-column field="name" [sortable]="true" [filterable]="true"></igx-column>
</igx-tree-grid>
typescript
@Component({
  selector: 'app-org-tree',
  imports: [IGX_TREE_GRID_DIRECTIVES],
  templateUrl: './org-tree.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class OrgTreeComponent {
  // 树形网格使用IgxTreeGridComponent
  treeGridRef = viewChild.required<IgxTreeGridComponent>('treeGrid');
  protected employees = signal<Employee[]>([]);
}
html
<igx-tree-grid #treeGrid
  [data]="employees()"
  primaryKey="id"
  foreignKey="managerId"
  height="600px">
  <igx-column field="name" [sortable]="true" [filterable]="true"></igx-column>
</igx-tree-grid>

Hierarchical Grid Example

分层网格示例

typescript
@Component({
  selector: 'app-company-grid',
  imports: [IGX_HIERARCHICAL_GRID_DIRECTIVES],
  templateUrl: './company-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CompanyGridComponent {
  // Use IgxHierarchicalGridComponent for hierarchical grids
  hGridRef = viewChild.required<IgxHierarchicalGridComponent>('hGrid');
  protected companies = signal<Company[]>([]);
}
html
<igx-hierarchical-grid #hGrid
  [data]="companies()"
  primaryKey="id"
  height="600px">
  <igx-column field="name" [sortable]="true"></igx-column>
  <igx-row-island key="orders" primaryKey="orderId">
    <igx-column field="orderId" [sortable]="true"></igx-column>
  </igx-row-island>
</igx-hierarchical-grid>
CRITICAL: Every programmatic example in this skill uses Flat Grid (
IgxGridComponent
) by default. For Tree Grid substitute
IgxTreeGridComponent
and
#treeGrid
. For Hierarchical Grid substitute
IgxHierarchicalGridComponent
and
#hGrid
. The sorting, filtering, and editing APIs are either the same or very similar across all three grid types (Flat, Tree, Hierarchical). Pivot Grid does NOT support standard sorting/filtering/editing APIs — see the Pivot Grid section. Grid Lite has its own lightweight sorting/filtering API — see the Grid Lite Data Operations section.
typescript
@Component({
  selector: 'app-company-grid',
  imports: [IGX_HIERARCHICAL_GRID_DIRECTIVES],
  templateUrl: './company-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CompanyGridComponent {
  // 分层网格使用IgxHierarchicalGridComponent
  hGridRef = viewChild.required<IgxHierarchicalGridComponent>('hGrid');
  protected companies = signal<Company[]>([]);
}
html
<igx-hierarchical-grid #hGrid
  [data]="companies()"
  primaryKey="id"
  height="600px">
  <igx-column field="name" [sortable]="true"></igx-column>
  <igx-row-island key="orders" primaryKey="orderId">
    <igx-column field="orderId" [sortable]="true"></igx-column>
  </igx-row-island>
</igx-hierarchical-grid>
重要提示: 本技能中的所有程序化示例默认使用普通网格(
IgxGridComponent
)。对于树形网格,请替换为
IgxTreeGridComponent
#treeGrid
;对于分层网格,请替换为
IgxHierarchicalGridComponent
#hGrid
。排序、筛选和编辑API在这三种网格类型(普通、树形、分层)中要么完全相同,要么高度相似。透视网格不支持标准排序/筛选/编辑API——请查看透视网格章节。Grid Lite有自己的轻量级排序/筛选API——请查看Grid Lite数据操作章节。

Sorting

排序

Applies to: Flat Grid, Tree Grid, and Hierarchical Grid. Pivot Grid uses dimension-level sorting instead (see Pivot Grid section). Grid Lite uses a different sorting API (
sort()
,
clearSort()
,
IgxGridLiteSortingExpression
) — see the Grid Lite Data Operations section.
Tree Grid behavior: sorting is applied per-level — children are sorted among their siblings, not globally flattened.
Hierarchical Grid behavior: each grid level sorts independently. Configure sorting on the
<igx-row-island>
to apply to all child grids at that level.
适用范围: 普通网格、树形网格、分层网格。透视网格使用维度级排序(请查看透视网格章节)。Grid Lite使用不同的排序API(
sort()
clearSort()
IgxGridLiteSortingExpression
)——请查看Grid Lite数据操作章节。
树形网格行为: 排序按层级应用——子项仅在同级间排序,不会全局扁平化。
分层网格行为: 每个网格层级独立排序。在
<igx-row-island>
上配置排序,将应用于该层级的所有子网格。

Template-Driven Sorting

模板驱动排序

Enable sorting on individual columns and optionally bind the sorting state:
html
<igx-grid #grid
  [data]="data()"
  [(sortingExpressions)]="sortExprs"
  [sortingOptions]="{ mode: 'single' }">
  <igx-column field="name" [sortable]="true"></igx-column>
  <igx-column field="date" dataType="date" [sortable]="true"></igx-column>
  <igx-column field="amount" dataType="number" [sortable]="true"></igx-column>
</igx-grid>
Sorting modes:
  • 'multiple'
    — multi-column sorting in order (default)
  • 'single'
    — only one column sorted at a time
为单个列启用排序,并可选择绑定排序状态:
html
<igx-grid #grid
  [data]="data()"
  [(sortingExpressions)]="sortExprs"
  [sortingOptions]="{ mode: 'single' }">
  <igx-column field="name" [sortable]="true"></igx-column>
  <igx-column field="date" dataType="date" [sortable]="true"></igx-column>
  <igx-column field="amount" dataType="number" [sortable]="true"></igx-column>
</igx-grid>
排序模式:
  • 'multiple'
    ——多列排序(按顺序,默认值)
  • 'single'
    ——同一时间仅对一列排序

Programmatic Sorting

程序化排序

typescript
import { SortingDirection } from 'igniteui-angular/grids/core';

// Sort a single column
this.gridRef().sort({ fieldName: 'name', dir: SortingDirection.Asc, ignoreCase: true });

// Sort multiple columns
this.gridRef().sort([
  { fieldName: 'category', dir: SortingDirection.Asc, ignoreCase: true },
  { fieldName: 'price', dir: SortingDirection.Desc, ignoreCase: false }
]);

// Clear sorting on one column
this.gridRef().clearSort('name');

// Clear all sorting
this.gridRef().clearSort();
typescript
import { SortingDirection } from 'igniteui-angular/grids/core';

// 对单个列排序
this.gridRef().sort({ fieldName: 'name', dir: SortingDirection.Asc, ignoreCase: true });

// 对多列排序
this.gridRef().sort([
  { fieldName: 'category', dir: SortingDirection.Asc, ignoreCase: true },
  { fieldName: 'price', dir: SortingDirection.Desc, ignoreCase: false }
]);

// 清除某一列的排序
this.gridRef().clearSort('name');

// 清除所有排序
this.gridRef().clearSort();

Sorting Events

排序事件

EventCancelablePayload
(sorting)
Yes
ISortingEventArgs
— set
event.cancel = true
to prevent
(sortingDone)
No
ISortingEventArgs
— fires after sort is applied
typescript
onSorting(event: ISortingEventArgs) {
  // Prevent sorting on a specific column
  if (event.fieldName === 'id') {
    event.cancel = true;
  }
}

onSortingDone(event: ISortingEventArgs) {
  console.log('Sorted by:', event.fieldName, event.dir);
  // Good place to trigger remote data fetch
}
事件是否可取消负载
(sorting)
ISortingEventArgs
——设置
event.cancel = true
可阻止排序
(sortingDone)
ISortingEventArgs
——排序完成后触发
typescript
onSorting(event: ISortingEventArgs) {
  // 阻止对特定列排序
  if (event.fieldName === 'id') {
    event.cancel = true;
  }
}

onSortingDone(event: ISortingEventArgs) {
  console.log('排序字段:', event.fieldName, '排序方向:', event.dir);
  // 在此触发远程数据获取是最佳时机
}

Custom Sorting Strategy

自定义排序策略

Implement
ISortingStrategy
to control how values are compared:
typescript
import { ISortingStrategy, SortingDirection } from 'igniteui-angular/grids/core';

class PrioritySortStrategy implements ISortingStrategy {
  private priorityOrder = ['Critical', 'High', 'Medium', 'Low'];

  sort(data: any[], fieldName: string, dir: SortingDirection): any[] {
    return data.sort((a, b) => {
      const indexA = this.priorityOrder.indexOf(a[fieldName]);
      const indexB = this.priorityOrder.indexOf(b[fieldName]);
      return dir === SortingDirection.Asc ? indexA - indexB : indexB - indexA;
    });
  }
}
html
<igx-column field="priority" [sortable]="true" [sortStrategy]="prioritySortStrategy"></igx-column>
实现
ISortingStrategy
以控制值的比较方式:
typescript
import { ISortingStrategy, SortingDirection } from 'igniteui-angular/grids/core';

class PrioritySortStrategy implements ISortingStrategy {
  private priorityOrder = ['Critical', 'High', 'Medium', 'Low'];

  sort(data: any[], fieldName: string, dir: SortingDirection): any[] {
    return data.sort((a, b) => {
      const indexA = this.priorityOrder.indexOf(a[fieldName]);
      const indexB = this.priorityOrder.indexOf(b[fieldName]);
      return dir === SortingDirection.Asc ? indexA - indexB : indexB - indexA;
    });
  }
}
html
<igx-column field="priority" [sortable]="true" [sortStrategy]="prioritySortStrategy"></igx-column>

Filtering

筛选

Docs: Filtering · Excel-Style · Advanced (substitute URL prefix per grid type)
Applies to: Flat Grid, Tree Grid, and Hierarchical Grid. Pivot Grid uses dimension-level filtering instead (see Pivot Grid section). Grid Lite uses a different filtering API (
filter()
,
clearFilter()
,
IgxGridLiteFilteringExpression
) — see the Grid Lite Data Operations section.
Tree Grid behavior: filtering is recursive — when a child matches, all its ancestor rows are shown (even if they don't match) and auto-expanded.
Hierarchical Grid behavior: each grid level filters independently. Configure filtering on the
<igx-row-island>
to apply to all child grids at that level.
文档: 筛选 · Excel风格筛选 · 高级筛选(根据网格类型替换URL前缀)
适用范围: 普通网格、树形网格、分层网格。透视网格使用维度级筛选(请查看透视网格章节)。Grid Lite使用不同的筛选API(
filter()
clearFilter()
IgxGridLiteFilteringExpression
)——请查看Grid Lite数据操作章节。
树形网格行为: 筛选是递归的——当子项匹配时,其所有祖先行都会显示(即使祖先不匹配)并自动展开。
分层网格行为: 每个网格层级独立筛选。在
<igx-row-island>
上配置筛选,将应用于该层级的所有子网格。

Filter Modes

筛选模式

ModeTemplate PropertyDescription
Quick Filter
[filterMode]="'quickFilter'"
Row of filter inputs above columns
Excel-Style
[filterMode]="'excelStyleFilter'"
Excel-like dropdown menus per column
Advanced
[allowAdvancedFiltering]="true"
Dialog with complex filter tree (AND/OR groups)
html
<!-- Excel-style filtering (most common enterprise pattern) -->
<igx-grid #grid
  [data]="data()"
  [allowFiltering]="true"
  [filterMode]="'excelStyleFilter'">
  <igx-column field="name" [filterable]="true"></igx-column>
  <igx-column field="status" [filterable]="true"></igx-column>
  <igx-column field="amount" dataType="number" [filterable]="true"></igx-column>
</igx-grid>
模式模板属性说明
快速筛选
[filterMode]="'quickFilter'"
列上方显示筛选输入行
Excel风格筛选
[filterMode]="'excelStyleFilter'"
每列提供类似Excel的下拉筛选菜单
高级筛选
[allowAdvancedFiltering]="true"
提供包含复杂筛选树(AND/OR组)的对话框
html
<!-- Excel风格筛选(最常用的企业级模式) -->
<igx-grid #grid
  [data]="data()"
  [allowFiltering]="true"
  [filterMode]="'excelStyleFilter'">
  <igx-column field="name" [filterable]="true"></igx-column>
  <igx-column field="status" [filterable]="true"></igx-column>
  <igx-column field="amount" dataType="number" [filterable]="true"></igx-column>
</igx-grid>

Programmatic Filtering

程序化筛选

typescript
import {
  IgxStringFilteringOperand,
  IgxNumberFilteringOperand,
  IgxDateFilteringOperand,
  IgxBooleanFilteringOperand,
  FilteringExpressionsTree,
  FilteringLogic
} from 'igniteui-angular/grids/core';

// Simple single-column filter
this.gridRef().filter('name', 'John', IgxStringFilteringOperand.instance().condition('contains'), true);

// Filter by number range
this.gridRef().filter('amount', 1000, IgxNumberFilteringOperand.instance().condition('greaterThan'));

// Filter by date
this.gridRef().filter('hireDate', new Date(2024, 0, 1), IgxDateFilteringOperand.instance().condition('after'));

// Clear single column filter
this.gridRef().clearFilter('name');

// Clear all filters
this.gridRef().clearFilter();
typescript
import {
  IgxStringFilteringOperand,
  IgxNumberFilteringOperand,
  IgxDateFilteringOperand,
  IgxBooleanFilteringOperand,
  FilteringExpressionsTree,
  FilteringLogic
} from 'igniteui-angular/grids/core';

// 简单的单列筛选
this.gridRef().filter('name', 'John', IgxStringFilteringOperand.instance().condition('contains'), true);

// 数值范围筛选
this.gridRef().filter('amount', 1000, IgxNumberFilteringOperand.instance().condition('greaterThan'));

// 日期筛选
this.gridRef().filter('hireDate', new Date(2024, 0, 1), IgxDateFilteringOperand.instance().condition('after'));

// 清除单列筛选
this.gridRef().clearFilter('name');

// 清除所有筛选
this.gridRef().clearFilter();

Complex Filtering (AND/OR Groups)

复杂筛选(AND/OR组)

Build multi-condition filters using
FilteringExpressionsTree
:
typescript
const tree = new FilteringExpressionsTree(FilteringLogic.And);
tree.filteringOperands = [
  {
    fieldName: 'status',
    condition: IgxStringFilteringOperand.instance().condition('equals'),
    searchVal: 'Active',
    ignoreCase: true
  },
  {
    fieldName: 'amount',
    condition: IgxNumberFilteringOperand.instance().condition('greaterThan'),
    searchVal: 500
  }
];
// Use filteringExpressionsTree for column-level programmatic filtering
this.gridRef().filteringExpressionsTree = tree;
this.gridRef().cdr.detectChanges();
NOTE: Use
filteringExpressionsTree
for programmatic column-level filtering.
advancedFilteringExpressionsTree
is only for the advanced filtering dialog (
[allowAdvancedFiltering]="true"
).
使用
FilteringExpressionsTree
构建多条件筛选:
typescript
const tree = new FilteringExpressionsTree(FilteringLogic.And);
tree.filteringOperands = [
  {
    fieldName: 'status',
    condition: IgxStringFilteringOperand.instance().condition('equals'),
    searchVal: 'Active',
    ignoreCase: true
  },
  {
    fieldName: 'amount',
    condition: IgxNumberFilteringOperand.instance().condition('greaterThan'),
    searchVal: 500
  }
];
// 使用filteringExpressionsTree进行列级程序化筛选
this.gridRef().filteringExpressionsTree = tree;
this.gridRef().cdr.detectChanges();
注意: 使用
filteringExpressionsTree
进行列级程序化筛选。
advancedFilteringExpressionsTree
仅适用于高级筛选对话框(
[allowAdvancedFiltering]="true"
)。

Global Filtering & Cross-Column Logic

全局筛选与跨列逻辑

typescript
// Filter all filterable columns at once with a search term
this.gridRef().filterGlobal('search term', IgxStringFilteringOperand.instance().condition('contains'), true);
Control the AND/OR logic between different column filters:
html
<!-- Default is AND — all column filters must match. Use OR to match any column filter -->
<igx-grid #grid [data]="data()" [allowFiltering]="true" [filteringLogic]="filteringLogic">
</igx-grid>
typescript
import { FilteringLogic } from 'igniteui-angular/grids/core';

// FilteringLogic.And (default) — row must match ALL column filters
// FilteringLogic.Or — row must match ANY column filter
filteringLogic = FilteringLogic.And;
typescript
// 使用搜索词同时筛选所有可筛选列
this.gridRef().filterGlobal('search term', IgxStringFilteringOperand.instance().condition('contains'), true);
控制不同列筛选之间的AND/OR逻辑:
html
<!-- 默认是AND——所有列筛选条件必须匹配。使用OR则匹配任一列筛选条件即可 -->
<igx-grid #grid [data]="data()" [allowFiltering]="true" [filteringLogic]="filteringLogic">
</igx-grid>
typescript
import { FilteringLogic } from 'igniteui-angular/grids/core';

// FilteringLogic.And(默认)——行必须匹配所有列筛选条件
// FilteringLogic.Or——行只需匹配任一列筛选条件
filteringLogic = FilteringLogic.And;

Filtering Events

筛选事件

EventCancelablePayload
(filtering)
Yes
IFilteringEventArgs
— set
event.cancel = true
to prevent
(filteringDone)
No
IFilteringEventArgs
— fires after filter is applied
typescript
onFilteringDone(event: IFilteringEventArgs) {
  // Trigger remote data fetch with new filter state
  this.loadFilteredData();
}
事件是否可取消负载
(filtering)
IFilteringEventArgs
——设置
event.cancel = true
可阻止筛选
(filteringDone)
IFilteringEventArgs
——筛选完成后触发
typescript
onFilteringDone(event: IFilteringEventArgs) {
  // 根据新的筛选状态触发远程数据获取
  this.loadFilteredData();
}

Available Filtering Operands by Data Type

按数据类型划分的可用筛选操作符

Operand ClassConditions
IgxStringFilteringOperand
contains
,
startsWith
,
endsWith
,
equals
,
doesNotEqual
,
doesNotContain
,
empty
,
notEmpty
,
null
,
notNull
,
in
IgxNumberFilteringOperand
equals
,
doesNotEqual
,
greaterThan
,
lessThan
,
greaterThanOrEqualTo
,
lessThanOrEqualTo
,
empty
,
notEmpty
,
null
,
notNull
,
in
IgxDateFilteringOperand
equals
,
doesNotEqual
,
before
,
after
,
today
,
yesterday
,
thisMonth
,
lastMonth
,
nextMonth
,
thisYear
,
lastYear
,
nextYear
,
empty
,
notEmpty
,
null
,
notNull
,
in
IgxBooleanFilteringOperand
all
,
true
,
false
,
empty
,
notEmpty
,
null
,
notNull
操作符类条件
IgxStringFilteringOperand
contains
,
startsWith
,
endsWith
,
equals
,
doesNotEqual
,
doesNotContain
,
empty
,
notEmpty
,
null
,
notNull
,
in
IgxNumberFilteringOperand
equals
,
doesNotEqual
,
greaterThan
,
lessThan
,
greaterThanOrEqualTo
,
lessThanOrEqualTo
,
empty
,
notEmpty
,
null
,
notNull
,
in
IgxDateFilteringOperand
equals
,
doesNotEqual
,
before
,
after
,
today
,
yesterday
,
thisMonth
,
lastMonth
,
nextMonth
,
thisYear
,
lastYear
,
nextYear
,
empty
,
notEmpty
,
null
,
notNull
,
in
IgxBooleanFilteringOperand
all
,
true
,
false
,
empty
,
notEmpty
,
null
,
notNull

Grouping (Flat Grid Only)

分组(仅普通网格)

Docs: Group By
NOTE: GroupBy is exclusive to the Flat Grid (
igx-grid
). Tree Grid uses its natural hierarchy. Hierarchical Grid uses row islands. Pivot Grid uses dimensions.
文档: 分组
注意: 分组功能仅适用于普通网格
igx-grid
)。树形网格使用自身的天然层级,分层网格使用行岛,透视网格使用维度。

Template-Driven Grouping

模板驱动分组

html
<igx-grid #grid
  [data]="data()"
  [groupsExpanded]="true">
  <igx-column field="category" [groupable]="true"></igx-column>
  <igx-column field="product" [groupable]="true"></igx-column>
  <igx-column field="price" dataType="number"></igx-column>

  <!-- Custom group row template -->
  <ng-template igxGroupByRow let-groupRow>
    {{ groupRow.expression.fieldName }}: {{ groupRow.value }}
    ({{ groupRow.records.length }} items)
  </ng-template>
</igx-grid>
html
<igx-grid #grid
  [data]="data()"
  [groupsExpanded]="true">
  <igx-column field="category" [groupable]="true"></igx-column>
  <igx-column field="product" [groupable]="true"></igx-column>
  <igx-column field="price" dataType="number"></igx-column>

  <!-- 自定义分组行模板 -->
  <ng-template igxGroupByRow let-groupRow>
    {{ groupRow.expression.fieldName }}: {{ groupRow.value }}
    ({{ groupRow.records.length }} 条数据)
  </ng-template>
</igx-grid>

Programmatic Grouping

程序化分组

typescript
import { SortingDirection } from 'igniteui-angular/grids/core';

// Group by a column
this.gridRef().groupBy({ fieldName: 'category', dir: SortingDirection.Asc, ignoreCase: true });

// Group by multiple columns
this.gridRef().groupBy([
  { fieldName: 'region', dir: SortingDirection.Asc, ignoreCase: true },
  { fieldName: 'category', dir: SortingDirection.Asc, ignoreCase: true }
]);

// Clear grouping on one column
this.gridRef().clearGrouping('category');

// Clear all grouping
this.gridRef().clearGrouping();

// Toggle group row expansion
this.gridRef().toggleGroup(groupRow);

// Expand/collapse all groups
this.gridRef().toggleAllGroupRows();
typescript
import { SortingDirection } from 'igniteui-angular/grids/core';

// 按某一列分组
this.gridRef().groupBy({ fieldName: 'category', dir: SortingDirection.Asc, ignoreCase: true });

// 按多列分组
this.gridRef().groupBy([
  { fieldName: 'region', dir: SortingDirection.Asc, ignoreCase: true },
  { fieldName: 'category', dir: SortingDirection.Asc, ignoreCase: true }
]);

// 清除某一列的分组
this.gridRef().clearGrouping('category');

// 清除所有分组
this.gridRef().clearGrouping();

// 切换分组行的展开状态
this.gridRef().toggleGroup(groupRow);

// 展开/折叠所有分组
this.gridRef().toggleAllGroupRows();

Group By Events

分组事件

EventDescription
(groupingDone)
Fires after grouping expressions change
事件说明
(groupingDone)
分组表达式更改后触发

Custom Group-By Key

自定义分组键

Control how values are grouped using a
groupingComparer
:
typescript
// Group dates by month instead of exact value
const monthGroupComparer = (a: Date, b: Date) => {
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() ? 0 : -1;
};
html
<igx-column field="orderDate" dataType="date" [groupable]="true" [groupingComparer]="monthGroupComparer"></igx-column>
使用
groupingComparer
控制值的分组方式:
typescript
// 按月份分组日期,而非精确值
const monthGroupComparer = (a: Date, b: Date) => {
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() ? 0 : -1;
};
html
<igx-column field="orderDate" dataType="date" [groupable]="true" [groupingComparer]="monthGroupComparer"></igx-column>

Paging

分页

Docs: Paging — Remote Paging (substitute URL prefix per grid type)
文档: 分页——远程分页(根据网格类型替换URL前缀)

Using the Paginator Component

使用分页器组件

html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  height="600px">
  <igx-column field="name"></igx-column>
  <igx-column field="amount" dataType="number"></igx-column>

  <igx-paginator
    [perPage]="15"
    [selectOptions]="[10, 15, 25, 50]"
    [displayDensity]="'comfortable'">
  </igx-paginator>
</igx-grid>
html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  height="600px">
  <igx-column field="name"></igx-column>
  <igx-column field="amount" dataType="number"></igx-column>

  <igx-paginator
    [perPage]="15"
    [selectOptions]="[10, 15, 25, 50]"
    [displayDensity]="'comfortable'">
  </igx-paginator>
</igx-grid>

Programmatic Paging

程序化分页

typescript
// Navigate pages
this.gridRef().paginator.page = 3;
this.gridRef().paginator.nextPage();
this.gridRef().paginator.previousPage();
this.gridRef().paginator.paginate(0); // go to first page

// Change page size
this.gridRef().paginator.perPage = 25;
typescript
// 切换页面
this.gridRef().paginator.page = 3;
this.gridRef().paginator.nextPage();
this.gridRef().paginator.previousPage();
this.gridRef().paginator.paginate(0); // 跳转到第一页

// 更改每页条数
this.gridRef().paginator.perPage = 25;

Paging Events

分页事件

EventDescription
(paging)
Fires before page changes (cancelable)
(pagingDone)
Fires after page has changed
(perPageChange)
Fires when page size changes
事件说明
(paging)
页面更改前触发(可取消)
(pagingDone)
页面更改后触发
(perPageChange)
每页条数更改时触发

Remote Paging

远程分页

typescript
export class RemotePagingComponent {
  data = signal<Product[]>([]);
  totalCount = signal(0);
  perPage = signal(15);

  gridRef = viewChild.required<IgxGridComponent>('grid');
  private dataService = inject(ProductService);

  constructor() {
    this.loadPage(0);
  }

  onPagingDone(event: IPageEventArgs) {
    this.loadPage(event.current);
  }

  onPerPageChange(perPage: number) {
    this.perPage.set(perPage);
    this.loadPage(0);
  }

  private loadPage(pageIndex: number) {
    const skip = pageIndex * this.perPage();
    this.dataService.getProducts({ skip, take: this.perPage() }).subscribe(result => {
      this.data.set(result.data);
      this.totalCount.set(result.totalCount);
    });
  }
}
html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  height="600px">
  <igx-column field="name"></igx-column>
  <igx-column field="price" dataType="number"></igx-column>

  <igx-paginator
    [perPage]="perPage()"
    [totalRecords]="totalCount()"
    (pagingDone)="onPagingDone($event)"
    (perPageChange)="onPerPageChange($event)">
  </igx-paginator>
</igx-grid>
typescript
export class RemotePagingComponent {
  data = signal<Product[]>([]);
  totalCount = signal(0);
  perPage = signal(15);

  gridRef = viewChild.required<IgxGridComponent>('grid');
  private dataService = inject(ProductService);

  constructor() {
    this.loadPage(0);
  }

  onPagingDone(event: IPageEventArgs) {
    this.loadPage(event.current);
  }

  onPerPageChange(perPage: number) {
    this.perPage.set(perPage);
    this.loadPage(0);
  }

  private loadPage(pageIndex: number) {
    const skip = pageIndex * this.perPage();
    this.dataService.getProducts({ skip, take: this.perPage() }).subscribe(result => {
      this.data.set(result.data);
      this.totalCount.set(result.totalCount);
    });
  }
}
html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  height="600px">
  <igx-column field="name"></igx-column>
  <igx-column field="price" dataType="number"></igx-column>

  <igx-paginator
    [perPage]="perPage()"
    [totalRecords]="totalCount()"
    (pagingDone)="onPagingDone($event)"
    (perPageChange)="onPerPageChange($event)">
  </igx-paginator>
</igx-grid>

Remote Data Operations

远程数据操作

Docs: Remote Data Operations (substitute URL prefix per grid type)
文档: 远程数据操作(根据网格类型替换URL前缀)

The Problem

问题背景

Grids perform sorting, filtering, and paging client-side by default. For large datasets, you must intercept these operations and delegate them to the server.
网格默认在客户端执行排序、筛选和分页。对于大型数据集,你需要拦截这些操作并将其委托给服务器处理。

Complete Remote Data Pattern

完整远程数据模式

This is the canonical pattern for server-side sorting, filtering, and virtualization. You must disable the built-in client-side sorting/filtering by applying
NoopSortingStrategy
and
NoopFilteringStrategy
on the grid:
typescript
import { Component, ChangeDetectionStrategy, signal, viewChild, inject, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
import {
  IForOfState,
  ISortingEventArgs,
  IFilteringExpressionsTree,
  NoopSortingStrategy,
  NoopFilteringStrategy
} from 'igniteui-angular/grids/core';
import { debounceTime, Subject } from 'rxjs';

@Component({
  selector: 'app-remote-grid',
  imports: [IGX_GRID_DIRECTIVES],
  templateUrl: './remote-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RemoteGridComponent {
  data = signal<Order[]>([]);
  totalCount = signal(0);
  isLoading = signal(false);

  // Noop strategies — disable built-in client-side sort/filter
  noopSort = NoopSortingStrategy.instance();
  noopFilter = NoopFilteringStrategy.instance();

  gridRef = viewChild.required<IgxGridComponent>('grid');
  private dataService = inject(OrderService);
  private destroyRef = inject(DestroyRef);

  private currentSort: ISortingEventArgs[] | undefined;
  private currentFilter: IFilteringExpressionsTree | undefined;

  // Debounce rapid dataPreLoad events during fast scrolling
  private dataPreLoad$ = new Subject<IForOfState>();

  constructor() {
    this.dataPreLoad$.pipe(
      debounceTime(150),
      takeUntilDestroyed(this.destroyRef)
    ).subscribe(event => {
      // NOTE: The first chunkSize will always be 0 — use a reasonable default
      const chunkSize = event.chunkSize || 15;
      this.loadData(event.startIndex, chunkSize);
    });

    this.loadData(0, 15);
  }

  onDataPreLoad(event: IForOfState) {
    this.dataPreLoad$.next(event);
  }

  onSortingDone(event: ISortingEventArgs) {
    this.currentSort = this.gridRef().sortingExpressions;
    this.loadData(0, 15);
  }

  onFilteringDone() {
    this.currentFilter = this.gridRef().filteringExpressionsTree;
    this.loadData(0, 15);
  }

  private loadData(skip: number, take: number) {
    this.isLoading.set(true);
    this.dataService.getOrders({
      skip,
      take,
      sort: this.currentSort,
      filter: this.currentFilter
    }).subscribe(result => {
      this.data.set(result.data);
      this.totalCount.set(result.total);
      this.isLoading.set(false);
    });
  }
}
html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'orderId'"
  [totalItemCount]="totalCount()"
  [isLoading]="isLoading()"
  [autoGenerate]="false"
  [allowFiltering]="true"
  [filterMode]="'excelStyleFilter'"
  [sortStrategy]="noopSort"
  [filterStrategy]="noopFilter"
  (dataPreLoad)="onDataPreLoad($event)"
  (sortingDone)="onSortingDone($event)"
  (filteringDone)="onFilteringDone()"
  height="600px">

  <igx-column field="orderId" header="Order ID" [sortable]="true"></igx-column>
  <igx-column field="customer" header="Customer" [sortable]="true" [filterable]="true"></igx-column>
  <igx-column field="orderDate" header="Date" dataType="date" [sortable]="true" [filterable]="true"></igx-column>
  <igx-column field="amount" header="Amount" dataType="number" [sortable]="true" [filterable]="true"></igx-column>
  <igx-column field="status" header="Status" [filterable]="true"></igx-column>
</igx-grid>
IMPORTANT:
[sortStrategy]="noopSort"
and
[filterStrategy]="noopFilter"
prevent the grid from applying sort/filter operations client-side. The grid still fires events (allowing you to send them to the server), but the local data remains untouched until you replace it.
这是服务器端排序、筛选和虚拟化的标准实现模式。你必须通过在网格上应用
NoopSortingStrategy
NoopFilteringStrategy
来禁用内置的客户端排序/筛选
typescript
import { Component, ChangeDetectionStrategy, signal, viewChild, inject, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
import {
  IForOfState,
  ISortingEventArgs,
  IFilteringExpressionsTree,
  NoopSortingStrategy,
  NoopFilteringStrategy
} from 'igniteui-angular/grids/core';
import { debounceTime, Subject } from 'rxjs';

@Component({
  selector: 'app-remote-grid',
  imports: [IGX_GRID_DIRECTIVES],
  templateUrl: './remote-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RemoteGridComponent {
  data = signal<Order[]>([]);
  totalCount = signal(0);
  isLoading = signal(false);

  // Noop策略——禁用内置客户端排序/筛选
  noopSort = NoopSortingStrategy.instance();
  noopFilter = NoopFilteringStrategy.instance();

  gridRef = viewChild.required<IgxGridComponent>('grid');
  private dataService = inject(OrderService);
  private destroyRef = inject(DestroyRef);

  private currentSort: ISortingEventArgs[] | undefined;
  private currentFilter: IFilteringExpressionsTree | undefined;

  // 快速滚动时,防抖处理频繁触发的dataPreLoad事件
  private dataPreLoad$ = new Subject<IForOfState>();

  constructor() {
    this.dataPreLoad$.pipe(
      debounceTime(150),
      takeUntilDestroyed(this.destroyRef)
    ).subscribe(event => {
      // 注意:第一个chunkSize始终为0——使用合理的默认值
      const chunkSize = event.chunkSize || 15;
      this.loadData(event.startIndex, chunkSize);
    });

    this.loadData(0, 15);
  }

  onDataPreLoad(event: IForOfState) {
    this.dataPreLoad$.next(event);
  }

  onSortingDone(event: ISortingEventArgs) {
    this.currentSort = this.gridRef().sortingExpressions;
    this.loadData(0, 15);
  }

  onFilteringDone() {
    this.currentFilter = this.gridRef().filteringExpressionsTree;
    this.loadData(0, 15);
  }

  private loadData(skip: number, take: number) {
    this.isLoading.set(true);
    this.dataService.getOrders({
      skip,
      take,
      sort: this.currentSort,
      filter: this.currentFilter
    }).subscribe(result => {
      this.data.set(result.data);
      this.totalCount.set(result.total);
      this.isLoading.set(false);
    });
  }
}
html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'orderId'"
  [totalItemCount]="totalCount()"
  [isLoading]="isLoading()"
  [autoGenerate]="false"
  [allowFiltering]="true"
  [filterMode]="'excelStyleFilter'"
  [sortStrategy]="noopSort"
  [filterStrategy]="noopFilter"
  (dataPreLoad)="onDataPreLoad($event)"
  (sortingDone)="onSortingDone($event)"
  (filteringDone)="onFilteringDone()"
  height="600px">

  <igx-column field="orderId" header="订单ID" [sortable]="true"></igx-column>
  <igx-column field="customer" header="客户" [sortable]="true" [filterable]="true"></igx-column>
  <igx-column field="orderDate" header="日期" dataType="date" [sortable]="true" [filterable]="true"></igx-column>
  <igx-column field="amount" header="金额" dataType="number" [sortable]="true" [filterable]="true"></igx-column>
  <igx-column field="status" header="状态" [filterable]="true"></igx-column>
</igx-grid>
重要提示:
[sortStrategy]="noopSort"
[filterStrategy]="noopFilter"
可防止网格在客户端执行排序/筛选操作。网格仍会触发事件(允许你将这些操作发送到服务器),但本地数据将保持不变,直到你用服务器返回的数据替换它。

Excel-Style Filtering with Remote Unique Values

远程数据场景下的Excel风格筛选

When using Excel-style filtering with remote data, provide a strategy to fetch unique column values from the server:
typescript
import { IColumnPipeArgs } from 'igniteui-angular/grids/core';

// Tell the grid how to load unique values for Excel-style filter lists
uniqueValuesStrategy = (column: any, tree: any, done: (values: any[]) => void) => {
  this.dataService.getUniqueValues(column.field).subscribe(values => done(values));
};
html
<igx-grid #grid
  [data]="data()"
  [uniqueColumnValuesStrategy]="uniqueValuesStrategy"
  [filterMode]="'excelStyleFilter'"
  [allowFiltering]="true">
</igx-grid>
在远程数据场景下使用Excel风格筛选时,需提供从服务器获取列唯一值的策略:
typescript
import { IColumnPipeArgs } from 'igniteui-angular/grids/core';

// 告知网格如何为Excel风格筛选列表加载唯一值
uniqueValuesStrategy = (column: any, tree: any, done: (values: any[]) => void) => {
  this.dataService.getUniqueValues(column.field).subscribe(values => done(values));
};
html
<igx-grid #grid
  [data]="data()"
  [uniqueColumnValuesStrategy]="uniqueValuesStrategy"
  [filterMode]="'excelStyleFilter'"
  [allowFiltering]="true">
</igx-grid>

Remote Data Service Example

远程数据服务示例

typescript
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface RemoteDataResult<T> {
  data: T[];
  total: number;
}

@Injectable({ providedIn: 'root' })
export class OrderService {
  private http = inject(HttpClient);
  private apiUrl = '/api/orders';

  getOrders(params: {
    skip: number;
    take: number;
    sort?: any[];
    filter?: any;
  }): Observable<RemoteDataResult<Order>> {
    let httpParams = new HttpParams()
      .set('skip', params.skip)
      .set('take', params.take);

    if (params.sort?.length) {
      httpParams = httpParams.set('sort', JSON.stringify(params.sort));
    }
    if (params.filter) {
      httpParams = httpParams.set('filter', JSON.stringify(params.filter));
    }

    return this.http.get<RemoteDataResult<Order>>(this.apiUrl, { params: httpParams });
  }
}
typescript
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface RemoteDataResult<T> {
  data: T[];
  total: number;
}

@Injectable({ providedIn: 'root' })
export class OrderService {
  private http = inject(HttpClient);
  private apiUrl = '/api/orders';

  getOrders(params: {
    skip: number;
    take: number;
    sort?: any[];
    filter?: any;
  }): Observable<RemoteDataResult<Order>> {
    let httpParams = new HttpParams()
      .set('skip', params.skip)
      .set('take', params.take);

    if (params.sort?.length) {
      httpParams = httpParams.set('sort', JSON.stringify(params.sort));
    }
    if (params.filter) {
      httpParams = httpParams.set('filter', JSON.stringify(params.filter));
    }

    return this.http.get<RemoteDataResult<Order>>(this.apiUrl, { params: httpParams });
  }
}

Key Points for Remote Data

远程数据实现关键点

  1. Set
    [totalItemCount]
    — the grid needs the total record count for correct virtual scrollbar sizing
  2. Use
    [isLoading]
    — shows a loading indicator while data is being fetched
  3. Apply
    NoopSortingStrategy
    and
    NoopFilteringStrategy
    — prevents the grid from performing client-side sorting/filtering, so the server results are displayed as-is
  4. Listen to
    (dataPreLoad)
    — fires when the user scrolls and the grid needs more rows; provides
    startIndex
    and
    chunkSize
    (first
    chunkSize
    will be 0 — use a fallback)
  5. Listen to
    (sortingDone)
    and
    (filteringDone)
    — reset to the beginning and re-fetch with new parameters
  6. Track current sort/filter state — store them so every
    loadData
    call includes the active criteria
  7. Debounce
    (dataPreLoad)
    — use
    debounceTime
    to avoid flooding the server during fast scrolling
  8. Use
    [uniqueColumnValuesStrategy]
    — when using Excel-style filtering, supply a callback to load unique column values from the server
  1. 设置
    [totalItemCount]
    ——网格需要总记录数来正确计算虚拟滚动条的尺寸
  2. 使用
    [isLoading]
    ——数据获取时显示加载指示器
  3. 应用
    NoopSortingStrategy
    NoopFilteringStrategy
    ——禁用客户端排序/筛选,确保服务器返回的结果直接展示
  4. 监听
    (dataPreLoad)
    事件
    ——用户滚动且网格需要更多数据时触发,提供
    startIndex
    chunkSize
    (第一个
    chunkSize
    为0时使用备选值)
  5. 监听
    (sortingDone)
    (filteringDone)
    事件
    ——重置到起始位置并使用新参数重新获取数据
  6. 跟踪当前排序/筛选状态——存储这些状态,确保每次
    loadData
    调用都包含当前的筛选/排序条件
  7. 防抖处理
    (dataPreLoad)
    事件
    ——使用
    debounceTime
    避免快速滚动时频繁请求服务器
  8. 使用
    [uniqueColumnValuesStrategy]
    ——使用Excel风格筛选时,提供从服务器加载列唯一值的回调函数

Virtualization

虚拟化

How It Works

工作原理

All Ignite UI grids use row and column virtualization by default. Only the visible rows and columns are rendered in the DOM, enabling smooth scrolling through millions of records.
所有Ignite UI网格默认使用行和列虚拟化。仅渲染可见的行和列,支持流畅滚动数百万条记录。

Requirements

要求

  • Set a fixed
    height
    on the grid (e.g.,
    height="600px"
    )
  • No additional configuration is needed — virtualization is automatic
  • Do not wrap the grid in a virtual scroll container
  • 为网格设置固定高度(例如
    height="600px"
  • 无需额外配置——虚拟化是自动启用的
  • 不要将网格包裹在虚拟滚动容器中

Remote Virtualization

远程虚拟化

For datasets too large to load entirely, combine virtualization with remote data:
html
<igx-grid #grid
  [data]="data()"
  [totalItemCount]="totalCount()"
  (dataPreLoad)="onDataPreLoad($event)"
  height="600px">
</igx-grid>
The
(dataPreLoad)
event fires with an
IForOfState
containing:
  • startIndex
    — the first visible row index
  • chunkSize
    — number of rows the grid needs
对于无法一次性加载的超大型数据集,将虚拟化与远程数据结合使用:
html
<igx-grid #grid
  [data]="data()"
  [totalItemCount]="totalCount()"
  (dataPreLoad)="onDataPreLoad($event)"
  height="600px">
</igx-grid>
(dataPreLoad)
事件触发时会携带
IForOfState
对象,包含:
  • startIndex
    ——第一个可见行的索引
  • chunkSize
    ——网格需要的行数

Editing Data Through the Grid

通过网格编辑数据

AGENT INSTRUCTION: When a user says they want to "edit data through the grid", "make the grid editable", or "allow CRUD in the grid", use this section to pick the right editing mode before writing any code.
代理指令: 当用户表示想要“通过网格编辑数据”、“让网格可编辑”或“在网格中实现CRUD操作”时,在编写代码前先使用本节内容选择合适的编辑模式。

Choosing an Editing Mode

选择编辑模式

ModeWhen to useKey properties
Cell editingEach cell saves immediately when the user confirms or leaves it. Good for quick single-field corrections.
[editable]="true"
on columns +
(cellEditDone)
Row editingUser edits multiple cells in a row and confirms/cancels the whole row at once. Best for most CRUD UIs.
[rowEditable]="true"
+
[editable]="true"
on columns +
(rowEditDone)
Batch editingAccumulate many changes across multiple rows with undo/redo, then commit or discard all at once.
[batchEditing]="true"
+
[rowEditable]="true"
Default recommendation: use row editing for most data management UIs (e.g., "edit available cars"). It prevents half-edited data from being visible and gives users a clear Done/Cancel flow per row.
模式使用场景关键属性
单元格编辑用户确认或离开单元格时立即保存该单元格的数据。适用于快速修改单个字段。列上设置
[editable]="true"
+
(cellEditDone)
事件
行编辑用户编辑一行中的多个单元格,然后一次性确认/取消整行的修改。最适合大多数CRUD界面设置
[rowEditable]="true"
+ 列上设置
[editable]="true"
+
(rowEditDone)
事件
批量编辑累积多行的多个修改,支持撤销/重做,然后一次性提交或丢弃所有修改。设置
[batchEditing]="true"
+
[rowEditable]="true"
默认推荐: 大多数数据管理界面(例如“编辑可用车辆”)使用行编辑。它可以避免半编辑状态的数据被展示,并为用户提供清晰的每行确认/取消流程。

Cell Editing (Immediate)

单元格编辑(即时保存)

The simplest mode. Each cell saves the moment the user tabs away or presses Enter.
typescript
import { Component, ChangeDetectionStrategy, signal, viewChild, inject } from '@angular/core';
import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
import { IGridEditDoneEventArgs } from 'igniteui-angular/grids/core';

@Component({
  selector: 'app-cars-grid',
  imports: [IGX_GRID_DIRECTIVES],
  templateUrl: './cars-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CarsGridComponent {
  gridRef = viewChild.required<IgxGridComponent>('grid');
  private carService = inject(CarService);
  protected cars = signal<Car[]>([]);

  constructor() {
    this.carService.getCars().subscribe(data => this.cars.set(data));
  }

  onCellEditDone(event: IGridEditDoneEventArgs) {
    // Persist the single-cell change immediately
    const updatedCar = { ...event.rowData, [event.column.field]: event.newValue };
    this.carService.updateCar(updatedCar).subscribe();
  }
}
html
<igx-grid #grid
  [data]="cars()"
  [primaryKey]="'id'"
  [autoGenerate]="false"
  (cellEditDone)="onCellEditDone($event)"
  height="600px">
  <igx-column field="make" header="Make" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="model" header="Model" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="year" header="Year" dataType="number" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="price" header="Price" dataType="number" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="available" header="Available" dataType="boolean" [editable]="true"></igx-column>
</igx-grid>
最简单的编辑模式。用户按Tab键离开或按Enter键时,立即保存单元格数据。
typescript
import { Component, ChangeDetectionStrategy, signal, viewChild, inject } from '@angular/core';
import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
import { IGridEditDoneEventArgs } from 'igniteui-angular/grids/core';

@Component({
  selector: 'app-cars-grid',
  imports: [IGX_GRID_DIRECTIVES],
  templateUrl: './cars-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CarsGridComponent {
  gridRef = viewChild.required<IgxGridComponent>('grid');
  private carService = inject(CarService);
  protected cars = signal<Car[]>([]);

  constructor() {
    this.carService.getCars().subscribe(data => this.cars.set(data));
  }

  onCellEditDone(event: IGridEditDoneEventArgs) {
    // 立即保存单个单元格的修改
    const updatedCar = { ...event.rowData, [event.column.field]: event.newValue };
    this.carService.updateCar(updatedCar).subscribe();
  }
}
html
<igx-grid #grid
  [data]="cars()"
  [primaryKey]="'id'"
  [autoGenerate]="false"
  (cellEditDone)="onCellEditDone($event)"
  height="600px">
  <igx-column field="make" header="品牌" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="model" header="型号" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="year" header="年份" dataType="number" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="price" header="价格" dataType="number" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="available" header="是否可用" dataType="boolean" [editable]="true"></igx-column>
</igx-grid>

Row Editing (Recommended for CRUD)

行编辑(推荐用于CRUD操作)

Users click into a row, edit cells, then click Done or Cancel — changes only apply when Done is pressed. An overlay toolbar appears automatically.
typescript
import { Component, ChangeDetectionStrategy, signal, viewChild, inject } from '@angular/core';
import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
import { IGridEditDoneEventArgs, IGridEditEventArgs, IRowDataEventArgs } from 'igniteui-angular/grids/core';

@Component({
  selector: 'app-cars-grid',
  imports: [IGX_GRID_DIRECTIVES],
  templateUrl: './cars-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CarsGridComponent {
  gridRef = viewChild.required<IgxGridComponent>('grid');
  private carService = inject(CarService);
  protected cars = signal<Car[]>([]);

  constructor() {
    this.carService.getCars().subscribe(data => this.cars.set(data));
  }

  onRowEditDone(event: IGridEditDoneEventArgs) {
    // event.newValue contains the full updated row object
    this.carService.updateCar(event.newValue).subscribe();
  }

  onRowAdded(event: IRowDataEventArgs) {
    // Persist the newly added row; optionally replace local data with server response
    this.carService.createCar(event.data).subscribe(created => {
      this.cars.update(cars => cars.map(c => c === event.data ? created : c));
    });
  }

  onRowDeleted(event: IRowDataEventArgs) {
    this.carService.deleteCar(event.data.id).subscribe();
  }

  addCar() {
    // Programmatically start a new row at the end
    this.gridRef().beginAddRowByIndex(this.cars().length);
  }

  deleteCar(carId: number) {
    this.gridRef().deleteRow(carId);
  }
}
html
<igx-grid #grid
  [data]="cars()"
  [primaryKey]="'id'"
  [autoGenerate]="false"
  [rowEditable]="true"
  (rowEditDone)="onRowEditDone($event)"
  (rowAdded)="onRowAdded($event)"
  (rowDeleted)="onRowDeleted($event)"
  height="600px">

  <igx-column field="make" header="Make" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="model" header="Model" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="year" header="Year" dataType="number" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="price" header="Price" dataType="number" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="available" header="Available" dataType="boolean" [editable]="true"></igx-column>

  <!-- Action strip: shows Edit and Delete buttons on row hover; Add Row button in toolbar -->
  <igx-action-strip>
    <igx-grid-editing-actions [addRow]="true"></igx-grid-editing-actions>
  </igx-action-strip>
</igx-grid>

<button (click)="addCar()">Add Car</button>
Key inputs summary:
  • [rowEditable]="true"
    — enables the Done/Cancel overlay per row
  • [editable]="true"
    on each
    igx-column
    — marks which fields the user can change
  • [primaryKey]
    required for editing to work
  • [autoGenerate]="false"
    — always define columns explicitly when editing is enabled so you control which fields are editable
  • <igx-action-strip>
    with
    <igx-grid-editing-actions>
    — adds hover Edit/Delete buttons and an optional Add Row button automatically
文档: 行编辑
用户点击某一行,编辑多个单元格,然后点击完成取消——仅当点击完成时,修改才会生效。网格会自动显示覆盖工具栏。
typescript
import { Component, ChangeDetectionStrategy, signal, viewChild, inject } from '@angular/core';
import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
import { IGridEditDoneEventArgs, IGridEditEventArgs, IRowDataEventArgs } from 'igniteui-angular/grids/core';

@Component({
  selector: 'app-cars-grid',
  imports: [IGX_GRID_DIRECTIVES],
  templateUrl: './cars-grid.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CarsGridComponent {
  gridRef = viewChild.required<IgxGridComponent>('grid');
  private carService = inject(CarService);
  protected cars = signal<Car[]>([]);

  constructor() {
    this.carService.getCars().subscribe(data => this.cars.set(data));
  }

  onRowEditDone(event: IGridEditDoneEventArgs) {
    // event.newValue包含完整的更新后行对象
    this.carService.updateCar(event.newValue).subscribe();
  }

  onRowAdded(event: IRowDataEventArgs) {
    // 保存新增的行;可选择用服务器返回的数据替换本地数据
    this.carService.createCar(event.data).subscribe(created => {
      this.cars.update(cars => cars.map(c => c === event.data ? created : c));
    });
  }

  onRowDeleted(event: IRowDataEventArgs) {
    this.carService.deleteCar(event.data.id).subscribe();
  }

  addCar() {
    // 程序化地在末尾添加新行
    this.gridRef().beginAddRowByIndex(this.cars().length);
  }

  deleteCar(carId: number) {
    this.gridRef().deleteRow(carId);
  }
}
html
<igx-grid #grid
  [data]="cars()"
  [primaryKey]="'id'"
  [autoGenerate]="false"
  [rowEditable]="true"
  (rowEditDone)="onRowEditDone($event)"
  (rowAdded)="onRowAdded($event)"
  (rowDeleted)="onRowDeleted($event)"
  height="600px">

  <igx-column field="make" header="品牌" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="model" header="型号" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="year" header="年份" dataType="number" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="price" header="价格" dataType="number" [editable]="true" [sortable]="true"></igx-column>
  <igx-column field="available" header="是否可用" dataType="boolean" [editable]="true"></igx-column>

  <!-- 操作条:鼠标悬停在行上时显示编辑和删除按钮;工具栏中显示添加行按钮 -->
  <igx-action-strip>
    <igx-grid-editing-actions [addRow]="true"></igx-grid-editing-actions>
  </igx-action-strip>
</igx-grid>

<button (click)="addCar()">添加车辆</button>
关键输入属性总结:
  • [rowEditable]="true"
    ——启用每行的完成/取消覆盖工具栏
  • 每个
    igx-column
    上设置
    [editable]="true"
    ——标记用户可修改的字段
  • [primaryKey]
    ——编辑功能必须设置该属性
  • [autoGenerate]="false"
    ——启用编辑时始终显式定义列,以便控制哪些字段可编辑
  • <igx-action-strip>
    搭配
    <igx-grid-editing-actions>
    ——自动添加悬停编辑/删除按钮,以及可选的添加行按钮

Programmatic Row Adding with Default Values

程序化添加带默认值的行

When starting a new row programmatically, pre-populate fields using
(cellEditEnter)
on the new row:
typescript
onCellEditEnter(event: IGridEditEventArgs) {
  if (event.isAddRow && event.column.field === 'available') {
    event.cellEditArgs.newValue = true; // default new cars to available
  }
  if (event.isAddRow && event.column.field === 'year') {
    event.cellEditArgs.newValue = new Date().getFullYear();
  }
}
html
<igx-grid #grid ... (cellEditEnter)="onCellEditEnter($event)">

程序化添加新行时,可使用新行的
(cellEditEnter)
事件预填充字段:
typescript
onCellEditEnter(event: IGridEditEventArgs) {
  if (event.isAddRow && event.column.field === 'available') {
    event.cellEditArgs.newValue = true; // 新增车辆默认设为可用
  }
  if (event.isAddRow && event.column.field === 'year') {
    event.cellEditArgs.newValue = new Date().getFullYear();
  }
}
html
<igx-grid #grid ... (cellEditEnter)="onCellEditEnter($event)">

Batch Editing & Transactions

批量编辑与事务

Docs: Batch Editing (substitute URL prefix per grid type)
Applies to: Flat Grid, Tree Grid, and Hierarchical Grid. Pivot Grid does NOT support batch editing. Use batch editing when users need to edit many rows at once and commit or discard all changes together, with undo/redo support.
文档: 批量编辑(根据网格类型替换URL前缀)
适用范围: 普通网格、树形网格、分层网格。透视网格不支持批量编辑。 当用户需要同时编辑多行数据,并支持提交/丢弃所有修改以及撤销/重做时,使用批量编辑。

Enabling Batch Editing

启用批量编辑

html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  [batchEditing]="true"
  [rowEditable]="true"
  height="600px">
  <igx-column field="name" [editable]="true"></igx-column>
  <igx-column field="price" dataType="number" [editable]="true"></igx-column>
  <igx-column field="quantity" dataType="number" [editable]="true"></igx-column>
</igx-grid>

<button (click)="commitChanges()">Save All</button>
<button (click)="undoLast()">Undo</button>
<button (click)="redoLast()">Redo</button>
<button (click)="discardAll()">Discard</button>
html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  [batchEditing]="true"
  [rowEditable]="true"
  height="600px">
  <igx-column field="name" [editable]="true"></igx-column>
  <igx-column field="price" dataType="number" [editable]="true"></igx-column>
  <igx-column field="quantity" dataType="number" [editable]="true"></igx-column>
</igx-grid>

<button (click)="commitChanges()">保存所有修改</button>
<button (click)="undoLast()">撤销</button>
<button (click)="redoLast()">重做</button>
<button (click)="discardAll()">丢弃所有修改</button>

Managing Transactions

管理事务

typescript
commitChanges() {
  // Exit any active edit before committing
  this.gridRef().endEdit(true);
  this.gridRef().transactions.commit(this.gridRef().data);
}

undoLast() {
  // Must exit edit mode before undo/redo
  this.gridRef().endEdit(true);
  this.gridRef().transactions.undo();
}

redoLast() {
  this.gridRef().endEdit(true);
  this.gridRef().transactions.redo();
}

discardAll() {
  this.gridRef().endEdit(false);
  this.gridRef().transactions.clear();
}
Use
canUndo
and
canRedo
to control button state:
html
<button (click)="commitChanges()" [disabled]="gridRef().transactions.getAggregatedChanges(false).length < 1">Save All</button>
<button (click)="undoLast()" [disabled]="!gridRef().transactions.canUndo">Undo</button>
<button (click)="redoLast()" [disabled]="!gridRef().transactions.canRedo">Redo</button>
<button (click)="discardAll()">Discard</button>
typescript
commitChanges() {
  // 提交前退出任何活跃的编辑状态
  this.gridRef().endEdit(true);
  this.gridRef().transactions.commit(this.gridRef().data);
}

undoLast() {
  // 撤销/重做前必须退出编辑模式
  this.gridRef().endEdit(true);
  this.gridRef().transactions.undo();
}

redoLast() {
  this.gridRef().endEdit(true);
  this.gridRef().transactions.redo();
}

discardAll() {
  this.gridRef().endEdit(false);
  this.gridRef().transactions.clear();
}
使用
canUndo
canRedo
控制按钮状态:
html
<button (click)="commitChanges()" [disabled]="gridRef().transactions.getAggregatedChanges(false).length < 1">保存所有修改</button>
<button (click)="undoLast()" [disabled]="!gridRef().transactions.canUndo">撤销</button>
<button (click)="redoLast()" [disabled]="!gridRef().transactions.canRedo">重做</button>
<button (click)="discardAll()">丢弃所有修改</button>

Transaction State

事务状态

typescript
// Check if there are pending changes
const hasPendingChanges = this.gridRef().transactions.getAggregatedChanges(false).length > 0;

// Get all pending transactions
const pending = this.gridRef().transactions.getAggregatedChanges(true);
// Each transaction has: { id, type ('add'|'update'|'delete'), newValue }
typescript
// 检查是否有未提交的修改
const hasPendingChanges = this.gridRef().transactions.getAggregatedChanges(false).length > 0;

// 获取所有未提交的事务
const pending = this.gridRef().transactions.getAggregatedChanges(true);
// 每个事务包含:{ id, type ('add'|'update'|'delete'), newValue }

Sending Batch Changes to Server

将批量修改发送到服务器

typescript
saveToServer() {
  const changes = this.gridRef().transactions.getAggregatedChanges(true);

  const adds = changes.filter(t => t.type === 'add').map(t => t.newValue);
  const updates = changes.filter(t => t.type === 'update').map(t => ({ id: t.id, ...t.newValue }));
  const deletes = changes.filter(t => t.type === 'delete').map(t => t.id);

  this.dataService.saveBatch({ adds, updates, deletes }).subscribe(() => {
    this.gridRef().transactions.commit(this.gridRef().data);
    this.gridRef().transactions.clear();
  });
}
typescript
saveToServer() {
  const changes = this.gridRef().transactions.getAggregatedChanges(true);

  const adds = changes.filter(t => t.type === 'add').map(t => t.newValue);
  const updates = changes.filter(t => t.type === 'update').map(t => ({ id: t.id, ...t.newValue }));
  const deletes = changes.filter(t => t.type === 'delete').map(t => t.id);

  this.dataService.saveBatch({ adds, updates, deletes }).subscribe(() => {
    this.gridRef().transactions.commit(this.gridRef().data);
    this.gridRef().transactions.clear();
  });
}

Excel-Style Editing Workflows

Excel风格编辑工作流

Inline Cell Editing with Validation

带验证的内联单元格编辑

html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  [batchEditing]="true"
  (cellEditDone)="onCellEditDone($event)">

  <igx-column field="name" [editable]="true" required></igx-column>
  <igx-column field="email" [editable]="true" [validators]="emailValidators"></igx-column>
  <igx-column field="quantity" dataType="number" [editable]="true" [validators]="quantityValidators"></igx-column>
</igx-grid>
typescript
import { Validators } from '@angular/forms';

emailValidators = [Validators.required, Validators.email];
quantityValidators = [Validators.required, Validators.min(0), Validators.max(9999)];

onCellEditDone(event: IGridEditDoneEventArgs) {
  // React to edits — e.g., recalculate totals
  if (event.column.field === 'quantity' || event.column.field === 'unitPrice') {
    this.recalculateRowTotal(event.rowID);
  }
}
html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  [batchEditing]="true"
  (cellEditDone)="onCellEditDone($event)">

  <igx-column field="name" [editable]="true" required></igx-column>
  <igx-column field="email" [editable]="true" [validators]="emailValidators"></igx-column>
  <igx-column field="quantity" dataType="number" [editable]="true" [validators]="quantityValidators"></igx-column>
</igx-grid>
typescript
import { Validators } from '@angular/forms';

emailValidators = [Validators.required, Validators.email];
quantityValidators = [Validators.required, Validators.min(0), Validators.max(9999)];

onCellEditDone(event: IGridEditDoneEventArgs) {
  // 响应编辑操作——例如重新计算总计
  if (event.column.field === 'quantity' || event.column.field === 'unitPrice') {
    this.recalculateRowTotal(event.rowID);
  }
}

Clipboard Paste for Bulk Edit

剪贴板粘贴批量编辑

Grids support paste from Excel/spreadsheets by default. Configure clipboard behavior:
html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  [batchEditing]="true"
  [clipboardOptions]="{ enabled: true, copyHeaders: true, copyFormatters: true, separator: '\t' }">
</igx-grid>
网格默认支持从Excel/电子表格粘贴数据。可配置剪贴板行为:
html
<igx-grid #grid
  [data]="data()"
  [primaryKey]="'id'"
  [batchEditing]="true"
  [clipboardOptions]="{ enabled: true, copyHeaders: true, copyFormatters: true, separator: '\t' }">
</igx-grid>

Row Adding via UI

通过UI添加行

typescript
// Flat Grid / Hierarchical Grid:
this.gridRef().beginAddRowByIndex(0);                // at top
this.gridRef().beginAddRowById('ALFKI');             // under a specific row
this.gridRef().beginAddRowByIndex(this.gridRef().data.length); // at end

// Tree Grid — add as child of a parent:
this.treeGridRef().addRow(newRowData, parentRowID);  // add row as child of parentRowID
this.treeGridRef().beginAddRowByIndex(3, true);      // add as child of row at index 3
Use with Action Strip for visual add/edit actions:
html
<igx-grid #grid [data]="data()" [primaryKey]="'id'" [rowEditable]="true">
  <igx-action-strip>
    <igx-grid-editing-actions [addRow]="true"></igx-grid-editing-actions>
  </igx-action-strip>
  <igx-column field="name" [editable]="true"></igx-column>
</igx-grid>
typescript
// 普通网格 / 分层网格:
this.gridRef().beginAddRowByIndex(0);                // 在顶部添加
this.gridRef().beginAddRowById('ALFKI');             // 在指定行下方添加
this.gridRef().beginAddRowByIndex(this.gridRef().data.length); // 在末尾添加

// 树形网格——作为父行的子项添加:
this.treeGridRef().addRow(newRowData, parentRowID);  // 添加为parentRowID的子行
this.treeGridRef().beginAddRowByIndex(3, true);      // 添加为索引3行的子行
搭配操作条使用,以提供可视化的添加/编辑操作:
html
<igx-grid #grid [data]="data()" [primaryKey]="'id'" [rowEditable]="true">
  <igx-action-strip>
    <igx-grid-editing-actions [addRow]="true"></igx-grid-editing-actions>
  </igx-action-strip>
  <igx-column field="name" [editable]="true"></igx-column>
</igx-grid>

Editing Events Reference

编辑事件参考

All grids fire a consistent sequence of events during cell and row editing:
EventFires WhenCancelable
(rowEditEnter)
Row enters edit modeYes
(cellEditEnter)
Cell enters edit mode (after
rowEditEnter
)
Yes
(cellEdit)
Cell value is about to be committedYes
(cellEditDone)
Cell value has been committedNo
(cellEditExit)
Cell exits edit modeNo
(rowEdit)
Row edit is about to be committed (Done button)Yes
(rowEditDone)
Row edit has been committedNo
(rowEditExit)
Row exits edit modeNo
Canceling
(cellEdit)
keeps the cell in edit mode — the value won't commit until Cancel is clicked:
typescript
onCellEdit(event: IGridEditEventArgs) {
  if (!event.valid) {
    event.cancel = true; // prevent committing invalid values
  }
}
所有网格在单元格和行编辑过程中都会触发一致的事件序列:
事件触发时机是否可取消
(rowEditEnter)
行进入编辑模式时
(cellEditEnter)
单元格进入编辑模式(在
rowEditEnter
之后)
(cellEdit)
单元格值即将提交时
(cellEditDone)
单元格值已提交时
(cellEditExit)
单元格退出编辑模式时
(rowEdit)
行编辑即将提交(点击完成按钮)时
(rowEditDone)
行编辑已提交时
(rowEditExit)
行退出编辑模式时
取消
(cellEdit)
事件会使单元格保持编辑状态——直到点击取消按钮,值才会提交:
typescript
onCellEdit(event: IGridEditEventArgs) {
  if (!event.valid) {
    event.cancel = true; // 阻止提交无效值
  }
}

Validation

验证

文档: 验证

Template-Driven Validation

模板驱动验证

Apply Angular validators directly on columns:
html
<igx-column field="email" [editable]="true" required email></igx-column>
<igx-column field="age" dataType="number" [editable]="true" required [min]="18" [max]="120"></igx-column>
Supported built-in validators:
required
,
min
,
max
,
email
,
minlength
,
maxlength
,
pattern
.
直接在列上应用Angular验证器:
html
<igx-column field="email" [editable]="true" required email></igx-column>
<igx-column field="age" dataType="number" [editable]="true" required [min]="18" [max]="120"></igx-column>
支持的内置验证器:
required
min
max
email
minlength
maxlength
pattern

Reactive Form Validation

响应式表单验证

Use the
formGroupCreated
event to add custom validators when a row enters edit mode:
html
<igx-grid #grid [data]="data()" [rowEditable]="true" [primaryKey]="'id'"
  (formGroupCreated)="onFormGroupCreated($event)">
</igx-grid>
typescript
onFormGroupCreated(event: IGridFormGroupCreatedEventArgs) {
  const { formGroup } = event;
  formGroup.get('endDate')?.addValidators(this.dateAfterValidator('startDate'));
}
使用
formGroupCreated
事件,在行进入编辑模式时添加自定义验证器:
html
<igx-grid #grid [data]="data()" [rowEditable]="true" [primaryKey]="'id'"
  (formGroupCreated)="onFormGroupCreated($event)">
</igx-grid>
typescript
onFormGroupCreated(event: IGridFormGroupCreatedEventArgs) {
  const { formGroup } = event;
  formGroup.get('endDate')?.addValidators(this.dateAfterValidator('startDate'));
}

Validation Service

验证服务

The grid exposes a
validation
service:
typescript
// Check if the grid is in a valid state
const isValid = this.gridRef().validation.valid;

// Get all records with validation errors
const invalid = this.gridRef().validation.getInvalid();

// Clear validation state for a specific record (or all if no id)
this.gridRef().validation.clear(recordId);
网格暴露了
validation
服务:
typescript
// 检查网格是否处于有效状态
const isValid = this.gridRef().validation.valid;

// 获取所有验证错误的记录
const invalid = this.gridRef().validation.getInvalid();

// 清除特定记录的验证状态(不传入id则清除所有)
this.gridRef().validation.clear(recordId);

Summaries

汇总

Docs: Summaries (substitute URL prefix per grid type)
文档: 汇总(根据网格类型替换URL前缀)

Built-In Summaries

内置汇总

html
<igx-column field="amount" dataType="number" [hasSummary]="true"></igx-column>
Default summaries by type:
  • number: Count, Min, Max, Sum, Average
  • date: Count, Earliest, Latest
  • string/boolean: Count
html
<igx-column field="amount" dataType="number" [hasSummary]="true"></igx-column>
按数据类型划分的默认汇总:
  • 数值类型: 计数、最小值、最大值、求和、平均值
  • 日期类型: 计数、最早日期、最晚日期
  • 字符串/布尔类型: 计数

Custom Summary Operand

自定义汇总操作符

typescript
import { IgxNumberSummaryOperand, IgxSummaryResult } from 'igniteui-angular/grids/core';

class RevenueSummary extends IgxNumberSummaryOperand {
  operate(data: number[]): IgxSummaryResult[] {
    const result = super.operate(data);
    result.push({
      key: 'margin',
      label: 'Avg Margin',
      summaryResult: data.length ? data.reduce((a, b) => a + b, 0) / data.length * 0.15 : 0
    });
    return result;
  }
}

// Use in component
revenueSummary = RevenueSummary;
html
<igx-column field="revenue" dataType="number" [hasSummary]="true" [summaries]="revenueSummary"></igx-column>
typescript
import { IgxNumberSummaryOperand, IgxSummaryResult } from 'igniteui-angular/grids/core';

class RevenueSummary extends IgxNumberSummaryOperand {
  operate(data: number[]): IgxSummaryResult[] {
    const result = super.operate(data);
    result.push({
      key: 'margin',
      label: '平均利润率',
      summaryResult: data.length ? data.reduce((a, b) => a + b, 0) / data.length * 0.15 : 0
    });
    return result;
  }
}

// 在组件中使用
revenueSummary = RevenueSummary;
html
<igx-column field="revenue" dataType="number" [hasSummary]="true" [summaries]="revenueSummary"></igx-column>

Summaries with Grouping

分组场景下的汇总

When grouping is enabled, summaries appear for each group. Control this with:
html
<igx-grid #grid
  [data]="data()"
  [showSummaryOnCollapse]="true"
  [summaryCalculationMode]="'childLevelsOnly'"
  [summaryPosition]="'bottom'">
</igx-grid>
启用分组时,每个分组都会显示汇总。可通过以下属性控制:
html
<igx-grid #grid
  [data]="data()"
  [showSummaryOnCollapse]="true"
  [summaryCalculationMode]="'childLevelsOnly'"
  [summaryPosition]="'bottom'">
</igx-grid>

State Persistence

状态持久化

Docs: State Persistence (substitute URL prefix per grid type)
文档: 状态持久化(根据网格类型替换URL前缀)

Saving and Restoring Grid State

保存与恢复网格状态

Use
IgxGridStateDirective
to persist sorting, filtering, grouping, paging, selection, and column state:
html
<igx-grid #grid [data]="data()" igxGridState>
  <igx-column field="name" [sortable]="true" [filterable]="true" [groupable]="true"></igx-column>
</igx-grid>
typescript
import { IgxGridStateDirective } from 'igniteui-angular/grids/grid';

export class StatefulGridComponent {
  gridState = viewChild.required(IgxGridStateDirective);

  saveState() {
    const state = this.gridState().getState();
    localStorage.setItem('gridState', state);
  }

  restoreState() {
    const state = localStorage.getItem('gridState');
    if (state) {
      this.gridState().setState(state);
    }
  }
}
使用
IgxGridStateDirective
持久化排序、筛选、分组、分页、选择和列状态:
html
<igx-grid #grid [data]="data()" igxGridState>
  <igx-column field="name" [sortable]="true" [filterable]="true" [groupable]="true"></igx-column>
</igx-grid>
typescript
import { IgxGridStateDirective } from 'igniteui-angular/grids/grid';

export class StatefulGridComponent {
  gridState = viewChild.required(IgxGridStateDirective);

  saveState() {
    const state = this.gridState().getState();
    localStorage.setItem('gridState', state);
  }

  restoreState() {
    const state = localStorage.getItem('gridState');
    if (state) {
      this.gridState().setState(state);
    }
  }
}

Selective State Features

选择性持久化功能

Control which features are persisted:
html
<igx-grid #grid [data]="data()" [igxGridState]="stateOptions">
</igx-grid>
typescript
stateOptions = {
  sorting: true,
  filtering: true,
  groupBy: true,
  paging: true,
  columns: true,
  cellSelection: false,    // skip selection state
  rowSelection: false,
  columnSelection: false,
  advancedFiltering: true,
  rowPinning: true,
  expansion: true
};
控制需要持久化的功能:
html
<igx-grid #grid [data]="data()" [igxGridState]="stateOptions">
</igx-grid>
typescript
stateOptions = {
  sorting: true,
  filtering: true,
  groupBy: true,
  paging: true,
  columns: true,
  cellSelection: false,    // 不持久化选择状态
  rowSelection: false,
  columnSelection: false,
  advancedFiltering: true,
  rowPinning: true,
  expansion: true
};

Restoring Custom Strategies

恢复自定义策略

IgxGridState
does not persist functions — this includes sorting strategies, filtering strategies, column formatters, summaries,
cellClasses
, and
cellStyles
. Use the
stateParsed
event to reapply these after restoring state:
typescript
restoreState() {
  const stateJson = localStorage.getItem('gridState');
  if (!stateJson) return;

  // Subscribe to stateParsed to reapply custom strategies before state is applied
  this.gridState().stateParsed.pipe(take(1)).subscribe(parsedState => {
    parsedState.sorting?.forEach(expr => expr.strategy = NoopSortingStrategy.instance());
  });

  this.gridState().setState(stateJson);
}
IgxGridState
不持久化函数——包括排序策略、筛选策略、列格式化器、汇总、
cellClasses
cellStyles
。使用
stateParsed
事件,在恢复状态后重新应用这些自定义内容:
typescript
restoreState() {
  const stateJson = localStorage.getItem('gridState');
  if (!stateJson) return;

  // 订阅stateParsed事件,在状态应用前重新应用自定义策略
  this.gridState().stateParsed.pipe(take(1)).subscribe(parsedState => {
    parsedState.sorting?.forEach(expr => expr.strategy = NoopSortingStrategy.instance());
  });

  this.gridState().setState(stateJson);
}

Restoring Column Templates

恢复列模板

Column templates are also not serialized. Use the
columnInit
event to reassign them:
typescript
@ViewChild('activeTemplate', { static: true }) public activeTemplate: TemplateRef<any>;

onColumnInit(column: IgxColumnComponent) {
  if (column.field === 'IsActive') {
    column.bodyTemplate = this.activeTemplate;
  }
}
html
<igx-grid #grid [data]="data()" igxGridState (columnInit)="onColumnInit($event)">
  <ng-template #activeTemplate igxCell let-val="val">
    <igx-checkbox [checked]="val"></igx-checkbox>
  </ng-template>
</igx-grid>
列模板也不会被序列化。使用
columnInit
事件重新分配模板:
typescript
@ViewChild('activeTemplate', { static: true }) public activeTemplate: TemplateRef<any>;

onColumnInit(column: IgxColumnComponent) {
  if (column.field === 'IsActive') {
    column.bodyTemplate = this.activeTemplate;
  }
}
html
<igx-grid #grid [data]="data()" igxGridState (columnInit)="onColumnInit($event)">
  <ng-template #activeTemplate igxCell let-val="val">
    <igx-checkbox [checked]="val"></igx-checkbox>
  </ng-template>
</igx-grid>

Tree Grid Data Operations

树形网格数据操作

Recursive Filtering Behavior

递归筛选行为

Tree Grid filtering is inclusive — when a child matches, all its ancestors are kept visible (marked as
isFilteredOutParent
) and auto-expanded. This is the default
TreeGridFilteringStrategy
.
html
<igx-tree-grid #treeGrid
  [data]="employees()"
  [primaryKey]="'id'"
  [foreignKey]="'managerId'"
  [allowFiltering]="true"
  [filterMode]="'excelStyleFilter'"
  height="600px">
  <igx-column field="name" [filterable]="true" [sortable]="true"></igx-column>
  <igx-column field="title" [filterable]="true"></igx-column>
</igx-tree-grid>
When you filter for
title = 'Developer'
, all ancestor rows are shown even though they don't match, and they're auto-expanded so you can see the matching children in context.
树形网格的筛选是包含式的——当子项匹配时,其所有祖先行都会保持可见(标记为
isFilteredOutParent
)并自动展开。这是默认的
TreeGridFilteringStrategy
行为。
html
<igx-tree-grid #treeGrid
  [data]="employees()"
  [primaryKey]="'id'"
  [foreignKey]="'managerId'"
  [allowFiltering]="true"
  [filterMode]="'excelStyleFilter'"
  height="600px">
  <igx-column field="name" [filterable]="true" [sortable]="true"></igx-column>
  <igx-column field="title" [filterable]="true"></igx-column>
</igx-tree-grid>
当你筛选
title = 'Developer'
时,所有祖先行都会显示(即使它们不匹配筛选条件),并且会自动展开,以便你在上下文中查看匹配的子项。

Per-Level Sorting

按层级排序

Tree Grid sorting is applied within each parent level — children are sorted among siblings, not globally flattened:
typescript
// This sorts employees within their respective manager, not globally
this.treeGridRef().sort({ fieldName: 'name', dir: SortingDirection.Asc, ignoreCase: true });
树形网格的排序在每个父层级内应用——子项仅在同级间排序,不会全局扁平化:
typescript
// 此代码会在每个经理的下属中对员工排序,而非全局排序
this.treeGridRef().sort({ fieldName: 'name', dir: SortingDirection.Asc, ignoreCase: true });

Tree Grid Batch Editing

树形网格批量编辑

Tree Grid uses
HierarchicalTransactionService
— each transaction carries a
path
array tracing the parent hierarchy, enabling proper undo/redo of nested changes:
html
<igx-tree-grid #treeGrid
  [data]="employees()"
  [primaryKey]="'id'"
  [foreignKey]="'managerId'"
  [batchEditing]="true"
  [rowEditable]="true"
  height="600px">
  <igx-column field="name" [editable]="true"></igx-column>
</igx-tree-grid>
typescript
// Add a row as child of a specific parent
this.treeGridRef().addRow({ id: 100, name: 'New Employee', managerId: 2 }, 2);

// Cascade delete — deleting a parent removes all descendants (default behavior)
this.treeGridRef().deleteRow(2); // deletes row 2 and all its children
树形网格使用
HierarchicalTransactionService
——每个事务都携带一个
path
数组,追踪父层级关系,支持正确地撤销/重做嵌套修改:
html
<igx-tree-grid #treeGrid
  [data]="employees()"
  [primaryKey]="'id'"
  [foreignKey]="'managerId'"
  [batchEditing]="true"
  [rowEditable]="true"
  height="600px">
  <igx-column field="name" [editable]="true"></igx-column>
</igx-tree-grid>
typescript
// 添加一行作为特定父行的子项
this.treeGridRef().addRow({ id: 100, name: '新员工', managerId: 2 }, 2);

// 级联删除——删除父行时会移除所有子项(默认行为)
this.treeGridRef().deleteRow(2); // 删除行2及其所有子行

Hierarchical Grid Data Operations

分层网格数据操作

Independent Grid Levels

独立的网格层级

Each level of a hierarchical grid has its own independent sorting, filtering, and paging state. Configure features on the
<igx-row-island>
blueprint:
html
<igx-hierarchical-grid #hGrid
  [data]="companies()"
  [primaryKey]="'id'"
  [allowFiltering]="true"
  [filterMode]="'excelStyleFilter'"
  height="600px">

  <igx-column field="name" [sortable]="true" [filterable]="true"></igx-column>

  <!-- Each row island defines column/feature config for that level -->
  <igx-row-island [key]="'orders'" [primaryKey]="'orderId'" [allowFiltering]="true" [rowEditable]="true">
    <igx-column field="orderId" [sortable]="true" [filterable]="true"></igx-column>
    <igx-column field="amount" dataType="number" [editable]="true"></igx-column>

    <igx-paginator [perPage]="10"></igx-paginator>
  </igx-row-island>
</igx-hierarchical-grid>
分层网格的每个层级都有独立的排序、筛选和分页状态。在
<igx-row-island>
模板上配置功能:
html
<igx-hierarchical-grid #hGrid
  [data]="companies()"
  [primaryKey]="'id'"
  [allowFiltering]="true"
  [filterMode]="'excelStyleFilter'"
  height="600px">

  <igx-column field="name" [sortable]="true" [filterable]="true"></igx-column>

  <!-- 每个行岛定义该层级的列/功能配置 -->
  <igx-row-island [key]="'orders'" [primaryKey]="'orderId'" [allowFiltering]="true" [rowEditable]="true">
    <igx-column field="orderId" [sortable]="true" [filterable]="true"></igx-column>
    <igx-column field="amount" dataType="number" [editable]="true"></igx-column>

    <igx-paginator [perPage]="10"></igx-paginator>
  </igx-row-island>
</igx-hierarchical-grid>

Accessing Child Grid Instances

获取子网格实例

To perform programmatic operations on child grids, use the
(gridCreated)
event:
typescript
onChildGridCreated(event: IGridCreatedEventArgs) {
  const childGrid = event.grid;
  // Example: apply a default sort to all child grids
  childGrid.sort({ fieldName: 'orderId', dir: SortingDirection.Desc, ignoreCase: false });
}
html
<igx-row-island [key]="'orders'" (gridCreated)="onChildGridCreated($event)">
  <igx-column field="orderId" [sortable]="true"></igx-column>
</igx-row-island>
要对子网格执行程序化操作,使用
(gridCreated)
事件:
typescript
onChildGridCreated(event: IGridCreatedEventArgs) {
  const childGrid = event.grid;
  // 示例:为所有子网格应用默认排序
  childGrid.sort({ fieldName: 'orderId', dir: SortingDirection.Desc, ignoreCase: false });
}
html
<igx-row-island [key]="'orders'" (gridCreated)="onChildGridCreated($event)">
  <igx-column field="orderId" [sortable]="true"></igx-column>
</igx-row-island>

Batch Editing Propagation

批量编辑的传播

Setting
[batchEditing]="true"
on the root hierarchical grid automatically propagates to all child grids:
html
<igx-hierarchical-grid #hGrid
  [data]="companies()"
  [primaryKey]="'id'"
  [batchEditing]="true"
  [rowEditable]="true">
  <!-- All child grids inherit batchEditing automatically -->
  <igx-row-island [key]="'departments'" [primaryKey]="'deptId'" [rowEditable]="true">
    <igx-column field="name" [editable]="true"></igx-column>
  </igx-row-island>
</igx-hierarchical-grid>
NOTE: Each child grid instance has its own
TransactionService
. Commits must be done per grid instance.
在根分层网格上设置
[batchEditing]="true"
,会自动将该配置传播到所有子网格:
html
<igx-hierarchical-grid #hGrid
  [data]="companies()"
  [primaryKey]="'id'"
  [batchEditing]="true"
  [rowEditable]="true">
  <!-- 所有子网格自动继承批量编辑配置 -->
  <igx-row-island [key]="'departments'" [primaryKey]="'deptId'" [rowEditable]="true">
    <igx-column field="name" [editable]="true"></igx-column>
  </igx-row-island>
</igx-hierarchical-grid>
注意: 每个子网格实例都有独立的
TransactionService
。提交操作需针对每个网格实例执行。

Pivot Grid Data Operations

透视网格数据操作

IMPORTANT: The Pivot Grid does NOT use standard sorting, filtering, editing, or paging APIs. All data operations are controlled through
pivotConfiguration
.
文档: 透视网格
重要提示: 透视网格不支持标准的排序、筛选、编辑或分页API。所有数据操作都通过
pivotConfiguration
控制。

Dimension-Based Filtering

基于维度的筛选

typescript
import { FilteringExpressionsTree, FilteringLogic, IgxStringFilteringOperand } from 'igniteui-angular/grids/core';

// Create a filter for a dimension
const regionFilter = new FilteringExpressionsTree(FilteringLogic.Or);
regionFilter.filteringOperands = [
  {
    fieldName: 'Region',
    condition: IgxStringFilteringOperand.instance().condition('equals'),
    searchVal: 'North America'
  },
  {
    fieldName: 'Region',
    condition: IgxStringFilteringOperand.instance().condition('equals'),
    searchVal: 'Europe'
  }
];

// Apply the filter to a dimension
this.pivotConfig.filters[0].filter = regionFilter;
// Notify the grid of the change
this.pivotGridRef().pipeTrigger++;
typescript
import { FilteringExpressionsTree, FilteringLogic, IgxStringFilteringOperand } from 'igniteui-angular/grids/core';

// 为维度创建筛选条件
const regionFilter = new FilteringExpressionsTree(FilteringLogic.Or);
regionFilter.filteringOperands = [
  {
    fieldName: 'Region',
    condition: IgxStringFilteringOperand.instance().condition('equals'),
    searchVal: 'North America'
  },
  {
    fieldName: 'Region',
    condition: IgxStringFilteringOperand.instance().condition('equals'),
    searchVal: 'Europe'
  }
];

// 将筛选条件应用到维度
this.pivotConfig.filters[0].filter = regionFilter;
// 通知网格配置已更改
this.pivotGridRef().pipeTrigger++;

Dimension-Based Sorting

基于维度的排序

typescript
// Sort a row dimension
this.pivotConfig.rows[0].sortDirection = SortingDirection.Desc;
this.pivotGridRef().pipeTrigger++;
typescript
// 对行维度排序
this.pivotConfig.rows[0].sortDirection = SortingDirection.Desc;
this.pivotGridRef().pipeTrigger++;

Key Pivot Grid Limitations

透视网格关键限制

  • No cell/row editing, batch editing, or row adding
  • No paging
  • No column pinning, moving, or hiding (columns are auto-generated)
  • No row dragging
  • No standard filtering (
    allowFiltering
    is forced to
    false
    )
  • No GroupBy (grouping is inherent via dimensions)
  • State persistence serializes the full
    pivotConfiguration
  • 不支持单元格/行编辑、批量编辑或添加行
  • 不支持分页
  • 不支持列固定、移动或隐藏(列是自动生成的)
  • 不支持行拖动
  • 不支持标准筛选(
    allowFiltering
    强制设为
    false
  • 不支持分组(分组通过维度天然实现)
  • 状态持久化会序列化完整的
    pivotConfiguration

Grid Lite Data Operations

Grid Lite数据操作

Grid Lite is a lightweight, open-source (MIT licensed) Web Component grid with an Angular wrapper. It supports sorting and filtering only — no editing, grouping, paging, summaries, selection, or export. Its API is different from the Flat/Tree/Hierarchical Grid APIs.
IMPORTANT: Grid Lite uses
IgxGridLiteSortingExpression
and
IgxGridLiteFilteringExpression
— NOT
ISortingExpression
or
FilteringExpressionsTree
from the enterprise grids.
Grid Lite是一个轻量级的开源(MIT协议)Web组件网格,提供Angular封装。它仅支持排序和筛选——不支持编辑、分组、分页、汇总、选择或导出。其API与普通/树形/分层网格的API完全不同
重要提示: Grid Lite使用
IgxGridLiteSortingExpression
IgxGridLiteFilteringExpression
——而非企业级网格的
ISortingExpression
FilteringExpressionsTree

Grid Lite Sorting

Grid Lite排序

typescript
import {
  IgxGridLiteComponent,
  IgxGridLiteSortingExpression,
  IgxGridLiteSortingOptions
} from 'igniteui-angular/grids/lite';

@Component({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  // ...
})
export class GridLiteSortExample {
  gridRef = viewChild<IgxGridLiteComponent<Product>>('grid');

  // Sorting options: mode can be 'single' or 'multiple'
  sortingOptions: IgxGridLiteSortingOptions = { mode: 'multiple' };

  // Initial sort state
  sortExprs: IgxGridLiteSortingExpression[] = [
    { key: 'name', direction: 'ascending' }
  ];

  sortByPrice() {
    // Sort programmatically (single expression or array)
    this.gridRef().sort({ key: 'price', direction: 'descending' });
  }

  clearAllSorts() {
    this.gridRef().clearSort(); // clear all
    // or: this.gridRef().clearSort('price'); // clear specific column
  }
}
html
<igx-grid-lite #grid
  [data]="data"
  [sortingOptions]="sortingOptions"
  [(sortingExpressions)]="sortExprs"
  (sorting)="onSorting($event)"
  (sorted)="onSorted($event)">
  <igx-grid-lite-column field="name" header="Name" sortable></igx-grid-lite-column>
  <igx-grid-lite-column field="price" header="Price" dataType="number" sortable></igx-grid-lite-column>
</igx-grid-lite>
Sort expression shape:
{ key: string, direction: 'ascending' | 'descending' | 'none' }
Sorting modes:
  • 'single'
    — only one column sorted at a time
  • 'multiple'
    — multi-column sorting
  • triState: true
    — allows cycling through ascending → descending → none
typescript
import {
  IgxGridLiteComponent,
  IgxGridLiteSortingExpression,
  IgxGridLiteSortingOptions
} from 'igniteui-angular/grids/lite';

@Component({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  // ...
})
export class GridLiteSortExample {
  gridRef = viewChild<IgxGridLiteComponent<Product>>('grid');

  // 排序选项:mode可以是'single'或'multiple'
  sortingOptions: IgxGridLiteSortingOptions = { mode: 'multiple' };

  // 初始排序状态
  sortExprs: IgxGridLiteSortingExpression[] = [
    { key: 'name', direction: 'ascending' }
  ];

  sortByPrice() {
    // 程序化排序(单个表达式或数组)
    this.gridRef().sort({ key: 'price', direction: 'descending' });
  }

  clearAllSorts() {
    this.gridRef().clearSort(); // 清除所有排序
    // 或者:this.gridRef().clearSort('price'); // 清除特定列的排序
  }
}
html
<igx-grid-lite #grid
  [data]="data"
  [sortingOptions]="sortingOptions"
  [(sortingExpressions)]="sortExprs"
  (sorting)="onSorting($event)"
  (sorted)="onSorted($event)">
  <igx-grid-lite-column field="name" header="名称" sortable></igx-grid-lite-column>
  <igx-grid-lite-column field="price" header="价格" dataType="number" sortable></igx-grid-lite-column>
</igx-grid-lite>
排序表达式结构:
{ key: string, direction: 'ascending' | 'descending' | 'none' }
排序模式:
  • 'single'
    ——同一时间仅对一列排序
  • 'multiple'
    ——多列排序
  • triState: true
    ——允许循环切换升序→降序→无排序

Grid Lite Filtering

Grid Lite筛选

typescript
import {
  IgxGridLiteComponent,
  IgxGridLiteFilteringExpression
} from 'igniteui-angular/grids/lite';

// Filter expression shape
const filters: IgxGridLiteFilteringExpression[] = [
  { key: 'price', condition: 'greaterThan', searchTerm: 100 },
  { key: 'name', condition: 'contains', searchTerm: 'Widget' }
];

// Programmatic filtering
this.gridRef().filter({ key: 'price', condition: 'greaterThan', searchTerm: 100 });
this.gridRef().clearFilter('price');
this.gridRef().clearFilter(); // clear all
html
<igx-grid-lite #grid
  [data]="data"
  [(filteringExpressions)]="filterExprs"
  (filtering)="onFiltering($event)"
  (filtered)="onFiltered($event)">
  <igx-grid-lite-column field="name" header="Name" filterable></igx-grid-lite-column>
  <igx-grid-lite-column field="price" header="Price" dataType="number" filterable></igx-grid-lite-column>
</igx-grid-lite>
Filter expression shape:
{ key: string, condition: string, searchTerm: any, criteria?: any[], caseSensitive?: boolean }
Filter conditions depend on
dataType
:
  • string:
    contains
    ,
    startsWith
    ,
    endsWith
    ,
    equals
    ,
    doesNotContain
    ,
    doesNotEqual
    ,
    empty
    ,
    notEmpty
    ,
    null
    ,
    notNull
  • number:
    equals
    ,
    doesNotEqual
    ,
    greaterThan
    ,
    lessThan
    ,
    greaterThanOrEqualTo
    ,
    lessThanOrEqualTo
    ,
    empty
    ,
    notEmpty
    ,
    null
    ,
    notNull
  • boolean:
    all
    ,
    true
    ,
    false
    ,
    empty
    ,
    notEmpty
    ,
    null
    ,
    notNull
  • date:
    equals
    ,
    doesNotEqual
    ,
    before
    ,
    after
    ,
    today
    ,
    yesterday
    ,
    thisMonth
    ,
    lastMonth
    ,
    nextMonth
    ,
    thisYear
    ,
    lastYear
    ,
    nextYear
    ,
    empty
    ,
    notEmpty
    ,
    null
    ,
    notNull
typescript
import {
  IgxGridLiteComponent,
  IgxGridLiteFilteringExpression
} from 'igniteui-angular/grids/lite';

// 筛选表达式结构
const filters: IgxGridLiteFilteringExpression[] = [
  { key: 'price', condition: 'greaterThan', searchTerm: 100 },
  { key: 'name', condition: 'contains', searchTerm: 'Widget' }
];

// 程序化筛选
this.gridRef().filter({ key: 'price', condition: 'greaterThan', searchTerm: 100 });
this.gridRef().clearFilter('price');
this.gridRef().clearFilter(); // 清除所有筛选
html
<igx-grid-lite #grid
  [data]="data"
  [(filteringExpressions)]="filterExprs"
  (filtering)="onFiltering($event)"
  (filtered)="onFiltered($event)">
  <igx-grid-lite-column field="name" header="名称" filterable></igx-grid-lite-column>
  <igx-grid-lite-column field="price" header="价格" dataType="number" filterable></igx-grid-lite-column>
</igx-grid-lite>
筛选表达式结构:
{ key: string, condition: string, searchTerm: any, criteria?: any[], caseSensitive?: boolean }
筛选条件取决于
dataType
  • 字符串:
    contains
    ,
    startsWith
    ,
    endsWith
    ,
    equals
    ,
    doesNotContain
    ,
    doesNotEqual
    ,
    empty
    ,
    notEmpty
    ,
    null
    ,
    notNull
  • 数值:
    equals
    ,
    doesNotEqual
    ,
    greaterThan
    ,
    lessThan
    ,
    greaterThanOrEqualTo
    ,
    lessThanOrEqualTo
    ,
    empty
    ,
    notEmpty
    ,
    null
    ,
    notNull
  • 布尔值:
    all
    ,
    true
    ,
    false
    ,
    empty
    ,
    notEmpty
    ,
    null
    ,
    notNull
  • 日期:
    equals
    ,
    doesNotEqual
    ,
    before
    ,
    after
    ,
    today
    ,
    yesterday
    ,
    thisMonth
    ,
    lastMonth
    ,
    nextMonth
    ,
    thisYear
    ,
    lastYear
    ,
    nextYear
    ,
    empty
    ,
    notEmpty
    ,
    null
    ,
    notNull

Grid Lite Remote Data Operations

Grid Lite远程数据操作

Grid Lite uses
dataPipelineConfiguration
— a callback-based approach (NOT noop strategies):
typescript
import { IgxGridLiteDataPipelineConfiguration } from 'igniteui-angular/grids/lite';

dataPipeline: IgxGridLiteDataPipelineConfiguration<Product> = {
  sort: async (params) => {
    // params.grid — the grid instance
    // params.data — current data array
    // params.type — 'sort'
    const result = await fetch(`/api/products?sort=${JSON.stringify(params.grid.sortingExpressions)}`);
    return await result.json();
  },
  filter: async (params) => {
    const result = await fetch(`/api/products?filter=${JSON.stringify(params.grid.filteringExpressions)}`);
    return await result.json();
  }
};
html
<igx-grid-lite #grid
  [data]="data"
  [dataPipelineConfiguration]="dataPipeline">
</igx-grid-lite>
Callbacks can be synchronous (return
T[]
) or asynchronous (return
Promise<T[]>
). When a
dataPipelineConfiguration
callback is provided for a given operation, the client-side pipeline for that operation is bypassed entirely.
Grid Lite使用
dataPipelineConfiguration
——基于回调的实现方式(而非noop策略):
typescript
import { IgxGridLiteDataPipelineConfiguration } from 'igniteui-angular/grids/lite';

dataPipeline: IgxGridLiteDataPipelineConfiguration<Product> = {
  sort: async (params) => {
    // params.grid — 网格实例
    // params.data — 当前数据数组
    // params.type — 'sort'
    const result = await fetch(`/api/products?sort=${JSON.stringify(params.grid.sortingExpressions)}`);
    return await result.json();
  },
  filter: async (params) => {
    const result = await fetch(`/api/products?filter=${JSON.stringify(params.grid.filteringExpressions)}`);
    return await result.json();
  }
};
html
<igx-grid-lite #grid
  [data]="data"
  [dataPipelineConfiguration]="dataPipeline">
</igx-grid-lite>
回调函数可以是同步的(返回
T[]
)或异步的(返回
Promise<T[]>
)。当为某个操作提供
dataPipelineConfiguration
回调时,该操作的客户端处理流程会被完全绕过。

Grid Lite Events

Grid Lite事件

EventCancelablePayload
(sorting)
Yes (
event.detail.cancel = true
)
Sorting expression about to be applied
(sorted)
NoSorting completed
(filtering)
Yes (
event.detail.cancel = true
)
Filter expression about to be applied
(filtered)
NoFiltering completed
事件是否可取消负载
(sorting)
是(
event.detail.cancel = true
即将应用的排序表达式
(sorted)
排序已完成
(filtering)
是(
event.detail.cancel = true
即将应用的筛选表达式
(filtered)
筛选已完成

Grid Lite Limitations (No Data Operations)

Grid Lite限制(不支持的数据操作)

These data operations are NOT available in Grid Lite:
  • Editing (cell, row, batch) — no
    [editable]
    , no
    beginEdit()
    , no transactions
  • Grouping — no
    groupBy()
    , no
    IgxGroupByRow
  • Paging — no
    IgxPaginatorComponent
  • Summaries — no
    IgxSummaryOperand
  • Selection — no
    rowSelection
    ,
    cellSelection
    , or
    columnSelection
  • State persistence — no
    IgxGridStateDirective
  • Export — no
    IgxExcelExporterService
    or
    IgxCsvExporterService
  • Advanced filtering — no
    advancedFilteringExpressionsTree
以下数据操作不支持在Grid Lite中使用:
  • 编辑(单元格、行、批量)——无
    [editable]
    属性、无
    beginEdit()
    方法、无事务管理
  • 分组——无
    groupBy()
    方法、无
    IgxGroupByRow
  • 分页——无
    IgxPaginatorComponent
  • 汇总——无
    IgxSummaryOperand
  • 选择——无
    rowSelection
    cellSelection
    columnSelection
  • 状态持久化——无
    IgxGridStateDirective
  • 导出——无
    IgxExcelExporterService
    IgxCsvExporterService
  • 高级筛选——无
    advancedFilteringExpressionsTree

Multi-Grid Coordination

多网格协同

Master-Detail Filtering

主从筛选

When using a master grid to drive a detail grid:
typescript
export class MasterDetailComponent {
  masterGrid = viewChild.required<IgxGridComponent>('masterGrid');
  orders = signal<Order[]>([]);
  selectedCustomer = signal<Customer | null>(null);
  customerOrders = signal<Order[]>([]);

  onRowSelectionChanging(event: IRowSelectionEventArgs) {
    const selectedId = event.newSelection[0];
    const customer = this.customers().find(c => c.id === selectedId);
    this.selectedCustomer.set(customer ?? null);

    if (customer) {
      this.dataService.getOrdersByCustomer(customer.id).subscribe(orders => {
        this.customerOrders.set(orders);
      });
    }
  }
}
html
<igx-grid #masterGrid
  [data]="customers()"
  [primaryKey]="'id'"
  [rowSelection]="'single'"
  (rowSelectionChanging)="onRowSelectionChanging($event)"
  height="300px">
  <igx-column field="name" header="Customer"></igx-column>
</igx-grid>

<igx-grid
  [data]="customerOrders()"
  [primaryKey]="'orderId'"
  height="300px">
  <igx-column field="orderId" header="Order"></igx-column>
  <igx-column field="amount" header="Amount" dataType="number"></igx-column>
</igx-grid>
使用主网格驱动从网格:
typescript
export class MasterDetailComponent {
  masterGrid = viewChild.required<IgxGridComponent>('masterGrid');
  orders = signal<Order[]>([]);
  selectedCustomer = signal<Customer | null>(null);
  customerOrders = signal<Order[]>([]);

  onRowSelectionChanging(event: IRowSelectionEventArgs) {
    const selectedId = event.newSelection[0];
    const customer = this.customers().find(c => c.id === selectedId);
    this.selectedCustomer.set(customer ?? null);

    if (customer) {
      this.dataService.getOrdersByCustomer(customer.id).subscribe(orders => {
        this.customerOrders.set(orders);
      });
    }
  }
}
html
<igx-grid #masterGrid
  [data]="customers()"
  [primaryKey]="'id'"
  [rowSelection]="'single'"
  (rowSelectionChanging)="onRowSelectionChanging($event)"
  height="300px">
  <igx-column field="name" header="客户"></igx-column>
</igx-grid>

<igx-grid
  [data]="customerOrders()"
  [primaryKey]="'orderId'"
  height="300px">
  <igx-column field="orderId" header="订单"></igx-column>
  <igx-column field="amount" header="金额" dataType="number"></igx-column>
</igx-grid>

Key Rules

核心规则

  1. Choose the right editing mode — cell editing (
    [editable]
    +
    (cellEditDone)
    ) for immediate per-cell saves; row editing (
    [rowEditable]="true"
    +
    (rowEditDone)
    ) for confirm/cancel per row (recommended default for CRUD); batch editing (
    [batchEditing]="true"
    ) for accumulate-then-commit with undo/redo
  2. [primaryKey]
    is required for all editing
    — row editing, batch editing, row adding, and row deletion all depend on it (Flat, Tree, Hierarchical, Pivot grids; NOT Grid Lite)
  3. Always set
    [autoGenerate]="false"
    when editing
    — define columns explicitly and mark each with
    [editable]="true"
    to control exactly what users can change
  4. Use the correct component type for
    viewChild
    IgxGridLiteComponent
    ,
    IgxGridComponent
    ,
    IgxTreeGridComponent
    ,
    IgxHierarchicalGridComponent
    , or
    IgxPivotGridComponent
  5. Import the correct directives/components
    IGX_GRID_DIRECTIVES
    ,
    IGX_TREE_GRID_DIRECTIVES
    ,
    IGX_HIERARCHICAL_GRID_DIRECTIVES
    ,
    IGX_PIVOT_GRID_DIRECTIVES
    , or individual Grid Lite imports (with
    CUSTOM_ELEMENTS_SCHEMA
    )
  6. Set
    dataType
    on every column
    — enables correct filtering operands, sorting behavior, and editors
  7. Cancelable events — use
    event.cancel = true
    in
    (sorting)
    ,
    (filtering)
    ,
    (cellEdit)
    ,
    (rowEdit)
    ,
    (paging)
    to prevent the action
  8. Use signals for data
    [data]="myData()"
    with
    signal<T[]>([])
  9. Remote data requires
    [totalItemCount]
    — without it, the virtual scrollbar won't size correctly
  10. Remote data requires noop strategies — apply
    NoopSortingStrategy
    and
    NoopFilteringStrategy
    to disable client-side operations when the server handles them
  11. Track sort/filter state for remote operations — store current expressions and include them in every server request
  12. Batch editing requires
    [primaryKey]
    — call
    endEdit(true)
    before
    transactions.undo()
    /
    redo()
    , commit via
    transactions.commit(data)
  13. Virtualization is automatic — don't wrap grids in virtual scroll containers; just set a fixed
    height
  14. Debounce rapid virtual scroll — use
    debounceTime
    on
    (dataPreLoad)
    to avoid flooding the server
  15. State persistence — use
    IgxGridStateDirective
    to save/restore sort, filter, group, and column configuration; functions (formatters, strategies, summaries) must be reapplied via
    stateParsed
    event
  16. Use
    filteringExpressionsTree
    for programmatic filtering
    advancedFilteringExpressionsTree
    is only for the advanced filtering dialog
  17. Validation — use template-driven validators on columns (
    required
    ,
    min
    ,
    max
    ,
    email
    ,
    pattern
    ) or reactive validators via
    (formGroupCreated)
  18. GroupBy is Flat Grid only — Tree Grid uses hierarchy, Hierarchical Grid uses row islands, Pivot Grid uses dimensions
  19. Tree Grid filtering is recursive — parents of matching children are always shown and auto-expanded
  20. Hierarchical Grid levels are independent — sorting/filtering/paging don't cascade; configure on
    <igx-row-island>
  21. Pivot Grid is read-only — no editing, paging, or standard filtering/sorting; use
    pivotConfiguration
    for all data operations
  22. Grid Lite has its own API — uses
    IgxGridLiteSortingExpression
    /
    IgxGridLiteFilteringExpression
    (NOT
    ISortingExpression
    /
    FilteringExpressionsTree
    ),
    dataPipelineConfiguration
    for remote ops (NOT noop strategies), and has no editing, grouping, paging, summaries, or selection
  1. 选择合适的编辑模式——单元格编辑(
    [editable]
    +
    (cellEditDone)
    )适用于即时保存单个单元格;行编辑(
    [rowEditable]="true"
    +
    (rowEditDone)
    )适用于每行的确认/取消流程(CRUD操作的默认推荐);批量编辑(
    [batchEditing]="true"
    )适用于累积修改后批量提交,支持撤销/重做
  2. [primaryKey]
    是所有编辑功能的必需项
    ——行编辑、批量编辑、添加行和删除行都依赖该属性(普通、树形、分层、透视网格;Grid Lite除外)
  3. 启用编辑时始终设置
    [autoGenerate]="false"
    ——显式定义列,并为每个列标记
    [editable]="true"
    ,以精确控制用户可修改的字段
  4. viewChild
    选择正确的组件类型
    ——
    IgxGridLiteComponent
    IgxGridComponent
    IgxTreeGridComponent
    IgxHierarchicalGridComponent
    IgxPivotGridComponent
  5. 导入正确的指令/组件——
    IGX_GRID_DIRECTIVES
    IGX_TREE_GRID_DIRECTIVES
    IGX_HIERARCHICAL_GRID_DIRECTIVES
    IGX_PIVOT_GRID_DIRECTIVES
    ,或Grid Lite的独立导入(需添加
    CUSTOM_ELEMENTS_SCHEMA
  6. 为每个列设置
    dataType
    ——启用正确的筛选操作符、排序行为和编辑器
  7. 可取消事件——在
    (sorting)
    (filtering)
    (cellEdit)
    (rowEdit)
    (paging)
    事件中使用
    event.cancel = true
    阻止操作执行
  8. 使用信号管理数据——使用
    [data]="myData()"
    搭配
    signal<T[]>([])
  9. 远程数据需设置
    [totalItemCount]
    ——否则虚拟滚动条无法正确计算尺寸
  10. 远程数据需使用noop策略——应用
    NoopSortingStrategy
    NoopFilteringStrategy
    ,在服务器处理操作时禁用客户端操作
  11. 为远程操作跟踪排序/筛选状态——存储当前表达式,并在每次服务器请求中包含这些状态
  12. 批量编辑需设置
    [primaryKey]
    ——调用
    endEdit(true)
    后再执行
    transactions.undo()
    /
    redo()
    ,通过
    transactions.commit(data)
    提交修改
  13. 虚拟化是自动启用的——不要将网格包裹在虚拟滚动容器中;只需设置固定高度
  14. 防抖处理快速滚动事件——对
    (dataPreLoad)
    事件使用
    debounceTime
    ,避免频繁请求服务器
  15. 状态持久化——使用
    IgxGridStateDirective
    保存/恢复排序、筛选、分组和列配置;函数(格式化器、策略、汇总)需通过
    stateParsed
    事件重新应用
  16. 使用
    filteringExpressionsTree
    进行程序化筛选
    ——
    advancedFilteringExpressionsTree
    仅适用于高级筛选对话框
  17. 验证——在列上使用模板驱动验证器(
    required
    min
    max
    email
    pattern
    ),或通过
    (formGroupCreated)
    使用响应式验证器
  18. 分组仅适用于普通网格——树形网格使用自身层级,分层网格使用行岛,透视网格使用维度
  19. 树形网格筛选是递归的——匹配子项时,其所有祖先行都会显示并自动展开
  20. 分层网格层级独立——排序/筛选/分页不会级联;需在
    <igx-row-island>
    上配置
  21. 透视网格是只读的——不支持编辑、分页或标准筛选/排序;所有数据操作通过
    pivotConfiguration
    控制
  22. Grid Lite有独立的API——使用
    IgxGridLiteSortingExpression
    /
    IgxGridLiteFilteringExpression
    (而非
    ISortingExpression
    /
    FilteringExpressionsTree
    ),远程操作使用
    dataPipelineConfiguration
    (而非noop策略),且不支持编辑、分组、分页、汇总或选择