You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:20:36