如何处理*ngFor渲染多列表项的独立Toggle功能
解决Angular *ngFor列表中Toggle按钮仅展开当前行的问题
嘿,我一眼就看出问题所在了——你所有的列表项都在共享同一个全局布尔变量 toggelFlagvfe!不管点击哪一行的按钮,这个变量的状态变化都会同步影响所有绑定它的元素,所以才会出现“点一个按钮全展开”的情况。
下面给你两种实用的解决方案,选哪种看你需求:
方案一:给每个数据项单独加展开状态(最简单直接)
直接在你的gDatas数组的每个对象里新增一个isExpanded属性,用来单独控制当前行的展开/收起状态:
组件类代码修改
export class VentClass { gDatas: any[]; constructor() { // 初始化数据时给每个item加上isExpanded,默认是收起状态(false) this.gDatas = [ {"ID":"85","Source":"Local","Eqpmnts":[{"ID":"10","CreatedBy":"jmzw"},{"ID":"10","CreatedBy":"jmzw"}], isExpanded: false}, {"ID":"86","Source":"Local","Eqpmnts":[{"ID":"10","CreatedBy":"jmzw"}], isExpanded: false}, {"ID":"87","Source":"EC","Eqpmnts":[],"isExpanded": false} ]; } toggleSection(item) { // 直接切换当前item的isExpanded状态,不用再判断true/false,一行搞定 item.isExpanded = !item.isExpanded; } }
模板代码修改
把模板里所有绑定toggelFlagvfe的地方,全部换成当前item的isExpanded:
<ion-row *ngFor="let item of gDatas"> <ion-col col-1> <button (click)="toggleSection(item)" detail-none [ngClass]="{'section-active1': item.isExpanded, 'section1': !item.isExpanded}"> <ion-icon item-left name="arrow-dropright" *ngIf="!item.isExpanded"></ion-icon> <ion-icon item-left name="arrow-dropdown" *ngIf="item.isExpanded"></ion-icon> </button> </ion-col> <ion-col col-2> <ion-input type="number" [(ngModel)]="item.ID" text-wrap></ion-input> </ion-col> <ion-col col-2> <ion-label>{{item.Source}} </ion-label> </ion-col> <!-- 这里改成用item.isExpanded控制详情显示 --> <div *ngIf="item.isExpanded"> <ion-grid > <ion-row *ngFor="let eqpm of item.Eqpmnts" nowrap> <ion-col> <ion-label>{{eqpm.ID}} </ion-label> <ion-label>{{eqpm.CreatedBy}} </ion-label> </ion-col> </ion-row> </ion-grid> </div> </ion-row>
方案二:用单独对象存状态(不修改原始数据)
如果不想改动你的原始gDatas数据,可以创建一个单独的对象,用每个item的ID作为键来存储对应的展开状态:
组件类代码修改
export class VentClass { gDatas: any[]; // 用对象来记录每个item的展开状态,键是item的ID expandedStates: {[key: string]: boolean} = {}; constructor() { this.gDatas = [ {"ID":"85","Source":"Local","Eqpmnts":[{"ID":"10","CreatedBy":"jmzw"},{"ID":"10","CreatedBy":"jmzw"}]}, {"ID":"86","Source":"Local","Eqpmnts":[{"ID":"10","CreatedBy":"jmzw"}]}, {"ID":"87","Source":"EC","Eqpmnts":[]} ]; // 初始化所有item为收起状态 this.gDatas.forEach(item => { this.expandedStates[item.ID] = false; }); } toggleSection(item) { // 切换对应ID的展开状态 this.expandedStates[item.ID] = !this.expandedStates[item.ID]; } }
模板代码修改
模板里绑定expandedStates[item.ID]来控制元素显示和按钮样式:
<ion-row *ngFor="let item of gDatas"> <ion-col col-1> <button (click)="toggleSection(item)" detail-none [ngClass]="{'section-active1': expandedStates[item.ID], 'section1': !expandedStates[item.ID]}"> <ion-icon item-left name="arrow-dropright" *ngIf="!expandedStates[item.ID]"></ion-icon> <ion-icon item-left name="arrow-dropdown" *ngIf="expandedStates[item.ID]"></ion-icon> </button> </ion-col> <ion-col col-2> <ion-input type="number" [(ngModel)]="item.ID" text-wrap></ion-input> </ion-col> <ion-col col-2> <ion-label>{{item.Source}} </ion-label> </ion-col> <div *ngIf="expandedStates[item.ID]"> <ion-grid > <ion-row *ngFor="let eqpm of item.Eqpmnts" nowrap> <ion-col> <ion-label>{{eqpm.ID}} </ion-label> <ion-label>{{eqpm.CreatedBy}} </ion-label> </ion-col> </ion-row> </ion-grid> </div> </ion-row>
这两种方案的核心都是让每个列表项拥有独立的状态变量,不再共享全局变量,这样点击某一行的按钮时,只会修改当前行对应的状态,完美实现你要的“仅展开当前行详情”的效果。
内容的提问来源于stack exchange,提问作者Jayesh
相关产品推荐
相关产品推荐

