Angular树形表格中如何获取单选按钮选中的行?
Angular树形表格中获取单选按钮选中行的解决方案
问题分析
你当前的代码里,单选按钮的selected属性仅做了单向绑定,但未在用户点击时更新节点状态,导致getSelected方法无法正确获取选中行。同时,原getSelected方法仅遍历根节点的后代,没有直接访问扁平化后的全量节点,逻辑存在疏漏。
修复步骤
1. 给单选按钮添加选中事件绑定
修改HTML中的mat-radio-button,新增(change)事件来同步节点的selected状态,确保同一组内仅一个选项被选中:
<mat-radio-button class="example-radio-button" [checked]="data.selected" [name]="data.group" [value]="data" (change)="onRadioChange(data, $event)" > </mat-radio-button>
2. 实现单选状态同步方法
在组件中添加onRadioChange方法,负责更新当前选中节点状态,并取消同一组内其他节点的选中状态:
onRadioChange(selectedNode: FoodNode, event: any) { // 筛选同一组的所有节点 const sameGroupNodes = this.treeControl.dataNodes.filter(node => node.group === selectedNode.group); // 取消组内所有节点的选中状态 sameGroupNodes.forEach(node => node.selected = false); // 设置当前节点为选中状态 selectedNode.selected = event.checked; }
3. 优化选中行获取逻辑
直接从treeControl.dataNodes获取所有扁平化后的节点,筛选出选中项:
getSelected() { const selectedItems = this.treeControl.dataNodes.filter(node => node.selected); console.log('选中的行:', selectedItems); return selectedItems; }
完整修改后的代码
HTML部分
<table mat-table [dataSource]="dataSourceTree" class="mat-elevation-z8"> <ng-container matColumnDef="name"> <th mat-header-cell *matHeaderCellDef> <span [style.paddingLeft.px]="40"> Name </span> </th> <td mat-cell *matCellDef="let data"> <div *ngIf="data.group" [style.marginLeft.px]="data.level * 20" style="display: inline" > <mat-radio-button class="example-radio-button" [checked]="data.selected" [name]="data.group" [value]="data" (change)="onRadioChange(data, $event)" > </mat-radio-button> </div> {{data.name}} </td> </ng-container> <ng-container matColumnDef="count"> <th mat-header-cell *matHeaderCellDef>Code</th> <td mat-cell *matCellDef="let data"> <div *ngIf="data.group" [style.marginLeft.px]="data.level * 20" style="display: inline" ></div> {{data.count}} </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <button (click)="getSelected()">show items selected</button>
TypeScript部分
import { FlatTreeControl } from '@angular/cdk/tree'; import { Component } from '@angular/core'; import { MatTreeFlatDataSource, MatTreeFlattener, } from '@angular/material/tree'; interface FoodNode { name: string; count?: number; children?: FoodNode[]; group?: number; selected?: boolean; expandable?: boolean; level?: number; } const TREE_DATA: FoodNode[] = [ { name: 'Math', count: 11, children: [ { name: 'MAT1A', count: 10, group: 1 }, { name: 'MAT1B', count: 20, group: 1 }, { name: 'MAT1C', count: 30, group: 1 }, ], }, { name: 'Physical', count: 22, children: [ { name: 'FIS1A', count: 40, group: 2 }, { name: 'FIS1B', count: 50, group: 2 }, { name: 'FIS1C', count: 60, group: 2 }, ], }, ]; @Component({ selector: 'table-basic-example', styleUrls: ['table-basic-example.css'], templateUrl: 'table-basic-example.html', }) export class TableBasicExample { displayedColumns: string[] = ['name', 'count']; private transformer = (node: FoodNode, level: number) => { return { expandable: !!node.children && node.children.length > 0, name: node.name, count: node.count, level: level, group: node.group, FoodNode: node.children, selected: node.selected || false, // 默认设置为未选中 }; }; treeControl = new FlatTreeControl<FoodNode>( (node) => node.level, (node) => node.expandable ); treeFlattener = new MatTreeFlattener( this.transformer, (node) => node.level, (node) => node.expandable, (node) => node.children ); dataSourceTree = new MatTreeFlatDataSource( this.treeControl, this.treeFlattener ); constructor() { this.dataSourceTree.data = TREE_DATA; this.treeControl.expandAll(); } hasChild = (_: number, node: FoodNode) => node.expandable; onRadioChange(selectedNode: FoodNode, event: any) { const sameGroupNodes = this.treeControl.dataNodes.filter(node => node.group === selectedNode.group); sameGroupNodes.forEach(node => node.selected = false); selectedNode.selected = event.checked; } getSelected() { const selectedItems = this.treeControl.dataNodes.filter(node => node.selected); console.log('选中的行:', selectedItems); return selectedItems; } }
关键说明
treeControl.dataNodes包含所有扁平化处理后的节点,直接遍历该数组可快速获取全量行数据onRadioChange方法确保同一组内仅一个单选按钮被选中,符合单选交互逻辑- 给
selected属性设置默认值false,避免初始状态下的undefined问题
内容的提问来源于stack exchange,提问作者slimterri
相关产品推荐
相关产品推荐

