Angular中如何动态填充嵌套数组结构的ProgramScorecardModel数组
问题:从.NET MVC转Angular开发,填充嵌套数组模型时出现TypeError错误
我从.NET MVC转Angular开发,需要创建和.NET中ProgramScorecardModel一致的嵌套数组结构数据模型,已经定义了对应的TypeScript接口,但用forEach结合async/await填充数据时,出现TypeError: Cannot set properties of undefined (setting 'programId')错误。proglist是包含programId、programName、reportingdate的数组,求正确的填充方法。
.NET数据模型代码
public class ProgramScorecardModel { public string programId { get; set; } public DateTime? reportingDate { get; set; } public string programName { get; set; } public IList<AB_ViewModel> AB_ViewModel { get; set; } public IList<CD_ViewModel> CD_ViewModel { get; set; } } public class AB_ViewModel { public string rating { get; set; } public DateTime? reportingDate { get; set; } public string comments { get; set; } } public class CD_ViewModel { public string rating { get; set; } public DateTime? reportingDate { get; set; } public string comments { get; set; } }
TypeScript接口代码
interface ProgramScorecardModel { programId: string; reportingDate: string; programName: string; AB_ViewModel: AB_ViewModel[]; CD_ViewModel: CD_ViewModel[]; } interface AB_ViewModel { rating: string; reportingDate: string; comments: string; } interface CD_ViewModel { rating: string; reportingDate: string; comments: string; }
出错的填充代码
let ProgramScorecard: ProgramScorecardModel[]=[] proglist.forEach(async (p, index) => { ProgramScorecard[index].programId = p.programId; ProgramScorecard[index].programName = p.programName; let AB_data = await this.GetMeasureForScorecard(p.programid,reportingdate); let CD_Data= await this.GetMeasureForScorecard(p.programid,reportingdate); ProgramScorecard[index].AB_ViewModel= AB_data ; ProgramScorecard[index].CD_ViewModel = CD_Data; });
解决方案
错误原因
ProgramScorecard是初始空数组,ProgramScorecard[index]一开始是undefined,直接给它的属性赋值必然触发错误。forEach不支持async/await的串行执行逻辑,会导致所有异步请求同时发起,且无法统一等待所有操作完成。
正确填充方法
方法1:使用map+Promise.all(推荐)
map返回每个元素对应的Promise,Promise.all等待所有异步操作完成,同时创建完整的数组元素:
async function fillScorecardData() { const ProgramScorecard: ProgramScorecardModel[] = await Promise.all( proglist.map(async (p) => { // 获取异步数据 const abData = await this.GetMeasureForScorecard(p.programId, p.reportingdate); const cdData = await this.GetMeasureForScorecard(p.programId, p.reportingdate); // 返回完整的模型对象 return { programId: p.programId, programName: p.programName, reportingDate: p.reportingdate, AB_ViewModel: abData, CD_ViewModel: cdData }; }) ); // 此处可直接使用填充好的ProgramScorecard数组 }
方法2:用for...of替代forEach(串行执行场景)
如果需要按顺序执行异步请求,用for...of可以天然支持await:
async function fillScorecardData() { const ProgramScorecard: ProgramScorecardModel[] = []; for (const p of proglist) { const abData = await this.GetMeasureForScorecard(p.programId, p.reportingdate); const cdData = await this.GetMeasureForScorecard(p.programId, p.reportingdate); const scorecardItem: ProgramScorecardModel = { programId: p.programId, programName: p.programName, reportingDate: p.reportingdate, AB_ViewModel: abData, CD_ViewModel: cdData }; ProgramScorecard.push(scorecardItem); } // 使用填充后的数组 }
额外优化点
- TypeScript接口中把
AB_ViewModel/CD_ViewModel的类型从any改为对应数组类型,获得类型检查的语法提示和错误预警。 - 注意变量名大小写一致性:原代码中
p.programid应为p.programId,和.NET模型字段保持一致,避免属性未定义的问题。 - 如果AB和CD的数据源逻辑不同,要确保调用对应的接口,避免重复调用同一个接口。
内容的提问来源于stack exchange,提问作者FlyFish
相关产品推荐
相关产品推荐

