Angular 13中如何将普通数组转为嵌套数组?求StackBlitz示例
在Angular 13中将一维数组按年份分组为嵌套数组
需求
需要将API返回的一维数据转换为按年份分组的嵌套结构,用于HTML循环渲染。
原始API数据
{ "data": [ { "Id": "17", "Year": "2020", "MonthName": "December", "Details": "Start the process ", "DisplayOrder": "3", "LanguageID": "1", "Hide": null }, { "Id": "16", "Year": "2020", "MonthName": "August", "Details": "Conduct an online ", "DisplayOrder": "2", "LanguageID": "1", "Hide": null }, { "Id": "15", "Year": "2020", "MonthName": "January", "Details": "Complete a minimum wage ", "DisplayOrder": "1", "LanguageID": "1", "Hide": null }, { "Id": "12", "Year": "2019", "MonthName": "September", "Details": "Start professions", "DisplayOrder": "3", "LanguageID": "1", "Hide": null }, { "Id": "11", "Year": "2019", "MonthName": "September", "Details": "Formulate Family Model", "DisplayOrder": "2", "LanguageID": "1", "Hide": null }, { "Id": "13", "Year": "2019", "MonthName": "October", "Details": "Complete technical research", "DisplayOrder": "1", "LanguageID": "1", "Hide": null }, { "Id": "14", "Year": "2019", "MonthName": "December", "Details": "Complete technical research service", "DisplayOrder": "1", "LanguageID": "1", "Hide": null }, { "Id": "10", "Year": "2019", "MonthName": "September", "Details": "Formulate Occupation", "DisplayOrder": "1", "LanguageID": "1", "Hide": null }, { "Id": "9", "Year": "2018", "MonthName": "October", "Details": "Approved officially", "DisplayOrder": "3", "LanguageID": "1", "Hide": null }, { "Id": "8", "Year": "2018", "MonthName": "October", "Details": "Start technical research", "DisplayOrder": "2", "LanguageID": "1", "Hide": null }, { "Id": "7", "Year": "2018", "MonthName": "October", "Details": "Publish a number completed", "DisplayOrder": "1", "LanguageID": "1", "Hide": null }, { "Id": "6", "Year": "2017", "MonthName": "October", "Details": "Formulate Commission", "DisplayOrder": "5", "LanguageID": "1", "Hide": null }, { "Id": "5", "Year": "2017", "MonthName": "May", "Details": "Complete the formulation", "DisplayOrder": "4", "LanguageID": "1", "Hide": null }, { "Id": "4", "Year": "2017", "MonthName": "April", "Details": " Initiate relevant Act.", "DisplayOrder": "3", "LanguageID": "1", "Hide": null }, { "Id": "3", "Year": "2017", "MonthName": "March", "Details": "Started the process employees", "DisplayOrder": "2", "LanguageID": "1", "Hide": null }, { "Id": "2", "Year": "2017", "MonthName": "February", "Details": "Started the process allowances", "DisplayOrder": "1", "LanguageID": "1", "Hide": null }, { "Id": "1", "Year": "2016", "MonthName": "October", "Details": "Members appointed", "DisplayOrder": "1", "LanguageID": "1", "Hide": null } ] }
期望的嵌套数组结构
{ "data": [ { "Year": "2020", "Month": [ { "Id": "17", "MonthName": "December", "Details": "Start the process", "DisplayOrder": "3", "LanguageID": "1", "Hide": null }, { "Id": "16", "MonthName": "August", "Details": "Conduct an online", "DisplayOrder": "2", "LanguageID": "1", "Hide": null }, { "Id": "15", "MonthName": "January", "Details": "Complete wage ", "DisplayOrder": "1", "LanguageID": "1", "Hide": null } ] }, { "Year": "2019", "Month": [ { "Id": "12", "MonthName": "September", "Details": "Start professions", "DisplayOrder": "3", "LanguageID": "1", "Hide": null }, { "Id": "11", "MonthName": "September", "Details": "Formulate Family Model", "DisplayOrder": "2", "LanguageID": "1", "Hide": null }, { "Id": "13", "MonthName": "October", "Details": "Complete technical research", "DisplayOrder": "1", "LanguageID": "1", "Hide": null }, { "Id": "14", "MonthName": "December", "Details": "Complete technical research service", "DisplayOrder": "1", "LanguageID": "1", "Hide": null }, { "Id": "10", "MonthName": "September", "Details": "Formulate Occupation", "DisplayOrder": "1", "LanguageID": "1", "Hide": null } ] }, { "Year": "2018", "Month": [ { "Id": "9", "MonthName": "October", "Details": "Approved officially", "DisplayOrder": "3", "LanguageID": "1", "Hide": null }, { "Id": "8", "MonthName": "October", "Details": "Start technical research", "DisplayOrder": "2", "LanguageID": "1", "Hide": null }, { "Id": "7", "MonthName": "October", "Details": "Publish a number completed", "DisplayOrder": "1", "LanguageID": "1", "Hide": null } ] }, { "Year": "2017", "Month": [ { "Id": "6", "MonthName": "October", "Details": "Formulate Commission", "DisplayOrder": "5", "LanguageID": "1", "Hide": null }, { "Id": "5", "MonthName": "May", "Details": "Complete the formulation", "DisplayOrder": "4", "LanguageID": "1", "Hide": null }, { "Id": "4", "MonthName": "April", "Details": " Initiate relevant Act.", "DisplayOrder": "3", "LanguageID": "1", "Hide": null }, { "Id": "3", "MonthName": "March", "Details": "Started the process employees", "DisplayOrder": "2", "LanguageID": "1", "Hide": null }, { "Id": "2", "MonthName": "February", "Details": "Started the process allowances", "DisplayOrder": "1", "LanguageID": "1", "Hide": null } ] }, { "Year": "2016", "Month": [ { "Id": "1", "MonthName": "October", "Details": "Members appointed", "DisplayOrder": "1", "LanguageID": "1", "Hide": null } ] } ] }
实现方案
1. 定义数据接口
在组件中定义对应的数据类型,确保类型安全:
// 原始数据条目类型 interface OriginalTimelineItem { Id: string; Year: string; MonthName: string; Details: string; DisplayOrder: string; LanguageID: string; Hide: string | null; } // 分组后的月份条目类型 interface GroupedMonthItem { Id: string; MonthName: string; Details: string; DisplayOrder: string; LanguageID: string; Hide: string | null; } // 分组后的年份条目类型 interface GroupedYearItem { Year: string; Month: GroupedMonthItem[]; }
2. 数据分组逻辑
在组件的ngOnInit生命周期钩子中处理数据分组,使用Array.reduce按年份聚合数据,同时排序:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-timeline', templateUrl: './timeline.component.html', styleUrls: ['./timeline.component.css'] }) export class TimelineComponent implements OnInit { // 模拟API返回的原始数据 originalData: OriginalTimelineItem[] = [/* 原始数据数组,即上面的data内容 */]; groupedData: GroupedYearItem[] = []; ngOnInit(): void { this.processGrouping(); } processGrouping(): void { // 第一步:按年份分组 const yearGroups = this.originalData.reduce((acc, item) => { const year = item.Year; // 构造月份条目,去掉Year字段 const monthItem: GroupedMonthItem = { Id: item.Id, MonthName: item.MonthName, Details: item.Details.trim(), // 清理详情文本的首尾空格 DisplayOrder: item.DisplayOrder, LanguageID: item.LanguageID, Hide: item.Hide }; if (!acc[year]) { acc[year] = []; } acc[year].push(monthItem); return acc; }, {} as Record<string, GroupedMonthItem[]>); // 第二步:转换为数组并排序 this.groupedData = Object.entries(yearGroups) .map(([year, months]) => ({ Year: year, // 月份条目按DisplayOrder降序排列 Month: months.sort((a, b) => parseInt(b.DisplayOrder) - parseInt(a.DisplayOrder)) })) // 年份按降序排列(最新年份在前) .sort((a, b) => parseInt(b.Year) - parseInt(a.Year)); } }
3. HTML模板渲染
在组件模板中使用*ngFor嵌套循环渲染分组后的数据:
<div class="timeline-container"> <div *ngFor="let yearGroup of groupedData" class="year-section"> <h2>{{ yearGroup.Year }}</h2> <div class="month-list"> <div *ngFor="let monthItem of yearGroup.Month" class="timeline-item"> <h3>{{ monthItem.MonthName }}</h3> <p>{{ monthItem.Details }}</p> <span class="order-tag">排序: {{ monthItem.DisplayOrder }}</span> </div> </div> </div> </div>
4. 基础样式(可选)
添加简单样式优化显示效果:
.timeline-container { max-width: 800px; margin: 2rem auto; padding: 0 1rem; } .year-section { margin-bottom: 2rem; border-bottom: 1px solid #eee; padding-bottom: 1rem; } .timeline-item { margin: 1rem 0; padding: 1rem; background-color: #f9f9f9; border-radius: 4px; } .order-tag { font-size: 0.8rem; color: #666; }
StackBlitz示例说明
可以创建一个Angular 13项目,将上述代码对应放入:
src/app/timeline/timeline.component.ts:组件逻辑src/app/timeline/timeline.component.html:模板代码src/app/timeline/timeline.component.css:样式代码- 在
app.module.ts中声明该组件,即可运行查看效果。
内容的提问来源于stack exchange,提问作者Anton96
相关产品推荐
相关产品推荐

