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

Angular中双向绑定二维数组动态赋值时出现undefined问题

解决Angular嵌套ngFor绑定二维数组时的Undefined错误

问题根源

你的问题出在异步数据加载时机和二维数组初始化逻辑两个核心点:

  1. 组件初始化时isSlotHidden仅被初始化为[[]],但异步请求未完成前,HTML已经开始遍历DriveDateSlots并尝试访问isSlotHidden[indexOfDate][indexOfSlot],此时目标索引对应的行/列还未创建,直接抛出undefined错误。
  2. 原TS代码中直接给isSlotHidden[i][j]赋值,但isSlotHidden[i]本身可能不存在(比如i=1时,初始数组只有第0行),导致无法访问子索引。

解决方案

1. 修正二维数组的构建逻辑

先初始化对应行的空数组,再填充元素,避免直接访问不存在的行:

// 变量声明改为空数组,移除不合理的初始[[]]
isSlotHidden: boolean[][] = [];
DriveSlot: any[] = [];
DriveDateSlots: any[] = []; // 假设这是你遍历日期用的数组

GetAllDriveSlots(): void {
    this.masterservice.GetAllDriveSlotDetail(this.DriveID).subscribe((response: any) => {
        this.DriveSlot = response;
        const uniqueDates = [...new Set(this.DriveSlot.map(obj => obj.driveSlotDate))];
        // 清空旧数据,避免残留脏数据
        this.isSlotHidden = [];
        let k = 0;

        for (let i = 0; i < uniqueDates.length; i++) {
            // 先初始化当前日期对应的行数组
            this.isSlotHidden[i] = [];
            let j = 0;
            while (k < this.DriveSlot.length && this.DriveSlot[k].driveSlotDate === uniqueDates[i]) {
                // 后续从数据库取数据时,把false替换为后端返回的对应字段,比如this.DriveSlot[k].isHidden
                this.isSlotHidden[i][j] = false;
                j++;
                k++;
            }
        }
        // 同步更新DriveDateSlots(假设该数组是基于uniqueDates生成的)
        this.DriveDateSlots = uniqueDates.map(date => ({ driveSlotDate: date }));
    }, (error: any) => {
        console.error('加载DriveSlots失败:', error);
    });
}

2. 添加加载状态控制HTML渲染

在异步请求完成前,不渲染绑定ngModel的元素,避免提前访问未初始化的数组:

<!-- 用*ngIf确保数据准备完成后再渲染 -->
<div *ngIf="isSlotHidden.length > 0 && DriveDateSlots.length > 0">
    <div *ngFor="let item of DriveDateSlots; let indexOfDate = index">
        <div *ngFor="let Slotitem of getTimeSlotDateWise(item.driveSlotDate); let indexOfSlot = index">
            <mat-slide-toggle [(ngModel)]="isSlotHidden[indexOfDate][indexOfSlot]">Hide</mat-slide-toggle>
        </div>
    </div>
</div>
<!-- 可选:添加加载提示 -->
<div *ngIf="isSlotHidden.length === 0">加载中...</div>

3. 优化模板方法调用(可选)

模板中频繁调用getTimeSlotDateWise会触发Angular多次变更检测,影响性能。建议提前构建日期-时段的映射关系:

// 新增映射变量,提前整理好日期对应的时段数据
dateToSlotsMap: Map<string, any[]> = new Map();

GetAllDriveSlots(): void {
    this.masterservice.GetAllDriveSlotDetail(this.DriveID).subscribe((response: any) => {
        this.DriveSlot = response;
        const uniqueDates = [...new Set(this.DriveSlot.map(obj => obj.driveSlotDate))];
        this.isSlotHidden = [];
        this.dateToSlotsMap.clear();

        let k = 0;
        for (let i = 0; i < uniqueDates.length; i++) {
            const date = uniqueDates[i];
            const slots: any[] = [];
            this.isSlotHidden[i] = [];
            let j = 0;
            while (k < this.DriveSlot.length && this.DriveSlot[k].driveSlotDate === date) {
                slots.push(this.DriveSlot[k]);
                // 后续从数据库取隐藏状态时替换这里的false
                this.isSlotHidden[i][j] = this.DriveSlot[k].isHidden || false;
                j++;
                k++;
            }
            this.dateToSlotsMap.set(date, slots);
        }
        this.DriveDateSlots = uniqueDates.map(date => ({ driveSlotDate: date }));
    });
}

模板中直接用映射获取时段:

<div *ngIf="isSlotHidden.length > 0 && DriveDateSlots.length > 0">
    <div *ngFor="let item of DriveDateSlots; let indexOfDate = index">
        <div *ngFor="let Slotitem of dateToSlotsMap.get(item.driveSlotDate); let indexOfSlot = index">
            <mat-slide-toggle [(ngModel)]="isSlotHidden[indexOfDate][indexOfSlot]">Hide</mat-slide-toggle>
        </div>
    </div>
</div>

关键注意点

  • 永远不要在模板中直接访问可能未初始化的数组索引,必须确保数组的行和列都已创建。
  • 异步数据加载完成前,用*ngIf或加载状态变量阻止渲染依赖该数据的组件。
  • 后续从数据库获取隐藏状态时,只需把this.isSlotHidden[i][j] = false替换为后端返回的对应字段即可。

内容的提问来源于stack exchange,提问作者Shekhar Mishra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:53:15