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

Angular 4带单选按钮的树形表格(Tree Grid)实现方案咨询

Hey there! Let's work through your Angular 4 requirement for an expandable table/grid with radio buttons per item. Here are some practical options and implementation steps tailored to your nested JSON data structure:

Component Libraries (Quickest Solution)

Since you're using Angular 4, these libraries have stable support for that version and can handle expandable rows + radio buttons out of the box:

1. Angular Material (v2.x for Angular 4)

Angular Material's MatTable paired with MatExpansionPanel is a great fit. You can structure each row to include an expansion panel that reveals child items from the SubGroup array, plus add MatRadioButton for selection.

  • How to set it up:
    • Define your table columns, including a column for the radio button and a trigger to expand/collapse rows.
    • Use [(ngModel)] to bind all radio buttons to a single selected item variable, ensuring mutual exclusivity across all rows (parent and child).
    • Nest a smaller table or list inside the expansion panel to render the SubGroup items, repeating the radio button pattern for child entries.

2. PrimeNG (v4.x for Angular 4)

PrimeNG's TreeTable is built exactly for nested data structures like yours. It has built-in expand/collapse functionality, and you can easily customize columns to include radio buttons.

  • Key perks:
    • The component automatically parses your SubGroup array to build the hierarchical structure—no extra recursion needed.
    • Use the p-radioButton component in a custom column template, set a shared name attribute or bind to a single selection variable to ensure only one item is selected at a time.

Manual Implementation (Full Control)

If you prefer to avoid third-party libraries, you can build this from scratch using Angular's core directives:

Step 1: Prepare Your Data

First, add an isExpanded flag to each item (and child items) to track the expand/collapse state. You can do this when fetching data:

addExpansionFlag(items: any[]): any[] {
  return items.map(item => ({
    ...item,
    isExpanded: false,
    SubGroup: item.SubGroup ? this.addExpansionFlag(item.SubGroup) : []
  }));
}

Step 2: Build the Template with Recursion

Use *ngFor and <ng-template> to render nested items recursively. Here's a simplified example:

<div class="table-container">
  <div *ngFor="let item of data" class="table-row">
    <!-- Parent Row -->
    <div class="row-content">
      <input 
        type="radio" 
        name="itemSelection" 
        [(ngModel)]="selectedItem" 
        [value]="item"
      >
      <span class="expand-trigger" (click)="item.isExpanded = !item.isExpanded">
        {{item.isExpanded ? '▼' : '▶'}} {{item.Name}}
      </span>
      <span class="description">{{item.Description}}</span>
    </div>

    <!-- Child Rows (Expanded) -->
    <div *ngIf="item.isExpanded && item.SubGroup.length" class="child-rows">
      <ng-container *ngTemplateOutlet="childRowTemplate; context:{ $implicit: item.SubGroup }"></ng-container>
    </div>
  </div>
</div>

<!-- Recursive Template for Child Items -->
<ng-template #childRowTemplate let-items>
  <div *ngFor="let subItem of items" class="table-row child-row">
    <div class="row-content">
      <input 
        type="radio" 
        name="itemSelection" 
        [(ngModel)]="selectedItem" 
        [value]="subItem"
      >
      <span class="expand-trigger" (click)="subItem.isExpanded = !subItem.isExpanded">
        {{subItem.isExpanded ? '▼' : '▶'}} {{subItem.Name}}
      </span>
      <span class="description">{{subItem.Description}}</span>
    </div>

    <!-- Nested Children -->
    <div *ngIf="subItem.isExpanded && subItem.SubGroup.length" class="child-rows">
      <ng-container *ngTemplateOutlet="childRowTemplate; context:{ $implicit: subItem.SubGroup }"></ng-container>
    </div>
  </div>
</ng-template>

Step 3: Component Logic

In your component class, initialize the data and selected item variable:

import { Component } from '@angular/core';
// Don't forget to import FormsModule in your module!

@Component({
  selector: 'app-expandable-radio-table',
  templateUrl: './expandable-radio-table.component.html',
  styleUrls: ['./expandable-radio-table.component.css']
})
export class ExpandableRadioTableComponent {
  rawData = { 
    "Id": 1, 
    "Name": "India", 
    "Description": "India", 
    "ParentId": 0, 
    "SubGroup": [ 
      { 
        "Id": 2, 
        "Name": "Mumbai", 
        "Description": "Mumbai", 
        "ParentId": 1,
        "SubGroup": []
      } 
    ]
  };

  data = this.addExpansionFlag([this.rawData]);
  selectedItem: any;

  addExpansionFlag(items: any[]): any[] {
    return items.map(item => ({
      ...item,
      isExpanded: false,
      SubGroup: item.SubGroup ? this.addExpansionFlag(item.SubGroup) : []
    }));
  }
}

Step 4: Style It

Add CSS to make it look like a table—align the content, indent child rows, and style the expand trigger:

.table-container {
  border: 1px solid #ddd;
  border-radius: 4px;
}

.table-row {
  border-bottom: 1px solid #ddd;
}

.row-content {
  display: flex;
  padding: 10px;
  align-items: center;
  gap: 10px;
}

.child-row .row-content {
  padding-left: 30px;
}

.expand-trigger {
  cursor: pointer;
  font-weight: 500;
}

.description {
  margin-left: auto;
  color: #666;
}

Key Notes

  • Don't forget to import FormsModule in your Angular module to use [(ngModel)] for radio buttons.
  • If your data comes from an API, modify the addExpansionFlag method to process the incoming data before rendering.
  • For mutual exclusivity, ensure all radio buttons share the same name attribute (or bind to the same ngModel variable, which handles this automatically).

内容的提问来源于stack exchange,提问作者Naveen Suryawanshi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:49:48