Angular(Taiga UI)表格复选框交互与分页状态处理问询
Taiga UI服务端分页表格复选框实现方案
一、主复选框三态实现
Taiga UI的tui-checkbox原生支持indeterminate(部分选中)状态,通过组件内的状态计算逻辑实现三态切换:
核心变量维护
selectedIds: Set<string>:存储跨分页已选中的文档IDisAllSelected: boolean:标记是否全选所有分页的文档excludedIds: Set<string>:全选所有时,存储需要排除的文档ID
三态计算逻辑
get masterCheckboxState(): boolean | null { if (this.isAllSelected) { // 全选所有时,有排除项则为部分选中,否则全选 return this.excludedIds.size > 0 ? null : true; } const currentPageIds = this.documents.map(doc => doc.id); const selectedInCurrent = currentPageIds.filter(id => this.selectedIds.has(id)); if (selectedInCurrent.length === currentPageIds.length) return true; return selectedInCurrent.length > 0 ? null : false; }
- 模板绑定
<tui-checkbox [(ngModel)]="masterCheckboxState" [indeterminate]="masterCheckboxState === null" (ngModelChange)="onMasterCheckboxChange($event)" ></tui-checkbox>
二、分页切换保留选中状态
通过全局存储选中状态,分页切换后重新匹配当前页数据的选中状态:
- 行复选框状态判断
isRowSelected(docId: string): boolean { if (this.isAllSelected) { return !this.excludedIds.has(docId); } return this.selectedIds.has(docId); }
- 分页切换逻辑
分页切换时仅请求当前页数据,无需修改选中状态存储变量,渲染行复选框时通过isRowSelected匹配状态:
<tui-checkbox [ngModel]="isRowSelected(doc.id)" (ngModelChange)="onRowCheckboxChange(doc.id, $event)" ></tui-checkbox>
三、全选场景下服务端通信优化
无需获取所有文档ID,通过标记+排除项的方式与服务端交互:
- 两种选中场景的请求格式
submitSelected(): void { let requestPayload; if (this.isAllSelected) { // 全选所有:传全选标记+排除ID+筛选条件(如有) requestPayload = { isAllSelected: true, excludedIds: Array.from(this.excludedIds), filter: this.currentFilter // 表格的筛选条件 }; } else { // 部分选中:仅传已选中ID集合 requestPayload = { selectedIds: Array.from(this.selectedIds) }; } // 调用服务端接口处理 this.documentService.processSelected(requestPayload).subscribe(); }
- 服务端处理逻辑
- 收到
isAllSelected: true时,根据筛选条件查询所有符合要求的文档,再排除excludedIds中的条目 - 收到
selectedIds时,直接处理指定ID的文档
四、完整核心代码示例
组件类
import { Component } from '@angular/core'; import { TuiTablePagination } from '@taiga-ui/addon-table'; interface Document { id: string; name: string; } @Component({ selector: 'app-document-table', templateUrl: './document-table.component.html', }) export class DocumentTableComponent { documents: Document[] = []; pagination = new TuiTablePagination({ page: 1, pageSize: 10 }); selectedIds = new Set<string>(); isAllSelected = false; excludedIds = new Set<string>(); currentFilter = {}; // 表格筛选条件 get masterCheckboxState(): boolean | null { if (this.isAllSelected) { return this.excludedIds.size > 0 ? null : true; } const currentPageIds = this.documents.map(doc => doc.id); const selectedInCurrent = currentPageIds.filter(id => this.selectedIds.has(id)); if (selectedInCurrent.length === currentPageIds.length) return true; return selectedInCurrent.length > 0 ? null : false; } isRowSelected(docId: string): boolean { if (this.isAllSelected) { return !this.excludedIds.has(docId); } return this.selectedIds.has(docId); } onMasterCheckboxChange(state: boolean | null): void { const currentPageIds = this.documents.map(doc => doc.id); if (state === true) { currentPageIds.forEach(id => this.selectedIds.add(id)); this.isAllSelected = false; this.excludedIds.clear(); } else if (state === false) { currentPageIds.forEach(id => this.selectedIds.delete(id)); this.isAllSelected = false; this.excludedIds.clear(); } } onRowCheckboxChange(docId: string, checked: boolean): void { if (this.isAllSelected) { checked ? this.excludedIds.delete(docId) : this.excludedIds.add(docId); } else { checked ? this.selectedIds.add(docId) : this.selectedIds.delete(docId); } } onPageChange(pagination: TuiTablePagination): void { this.pagination = pagination; this.loadDocuments(); } loadDocuments(): void { // 调用服务端接口加载当前页数据 // this.documentService.getDocuments(this.pagination, this.currentFilter).subscribe(res => { // this.documents = res.data; // }); } selectAllPages(): void { this.isAllSelected = true; this.selectedIds.clear(); this.excludedIds.clear(); } submitSelected(): void { const requestPayload = this.isAllSelected ? { isAllSelected: true, excludedIds: Array.from(this.excludedIds), filter: this.currentFilter } : { selectedIds: Array.from(this.selectedIds) }; // this.documentService.processSelected(requestPayload).subscribe(); } }
模板
<tui-table [data]="documents"> <thead> <tr> <th> <tui-checkbox [(ngModel)]="masterCheckboxState" [indeterminate]="masterCheckboxState === null" (ngModelChange)="onMasterCheckboxChange($event)" ></tui-checkbox> </th> <th>文档名称</th> </tr> </thead> <tbody> <tr *ngFor="let doc of documents"> <td> <tui-checkbox [ngModel]="isRowSelected(doc.id)" (ngModelChange)="onRowCheckboxChange(doc.id, $event)" ></tui-checkbox> </td> <td>{{ doc.name }}</td> </tr> </tbody> </tui-table> <tui-table-pagination [pagination]="pagination" (paginationChange)="onPageChange($event)" ></tui-table-pagination> <div style="margin-top: 16px;"> <button tuiButton (click)="selectAllPages()">全选所有分页</button> <button tuiButton (click)="submitSelected()" style="margin-left: 8px;">提交选中</button> </div>
内容的提问来源于stack exchange,提问作者Vladislav Kochurko
相关产品推荐
相关产品推荐

