Angular 17 应用程序连接到后端的 ExpressJS 应用程序。
Angular 应用程序组件:
export class CategoriesService {
private baseUrl = 'http://localhost:3000/api/categories';
private httpClient = inject(HttpClient);
async getAll() {
return firstValueFrom(
this.httpClient.get<Category[]>(this.baseUrl)
);
}
getByCategoryTitle(categoryTitle: string) {
return firstValueFrom(this.httpClient.get<Category[]>(`${this.baseUrl}/${categoryTitle}`));
}
}
export class ItemsService {
private baseUrl = `${environment.apiUrl}/items`;
constructor(private httpClient: HttpClient) { }
async getAll() {
return firstValueFrom(
this.httpClient.get<Item[]>(this.baseUrl)
);
}
}
export interface Item {
id: number;
organization: string;
title: string;
stDate: string;
endDate: string;
description: string;
categoryTitle: string;
categoryId: number;
}
export interface Category {
categoryId: number;
categoryTitle: string;
}
export class CardItemComponent {
@Input() item: Item | null = null;
itemsService = inject(ItemsService);
}
@if (item) {
<div class="item">
<p class="title" id="org">Organization: <span>{{item.organization}}</span></p>
<p class="title" id="title">Project: <span>{{item.title}}</span></p>
<p class="title" id="st-date">Start date: <span>{{item.stDate}}</span></p>
<p class="title" id="end-date">End date: <span>{{item.endDate}}</span></p>
<p class="title" id="description">Description: <span>{{item.description}}</span>
</p>
<hr>
</div>
}
export class ListItemsComponent {
router = inject(Router);
//----------- DATA-----------//
categories: Category[] = [];
allCategories: Item[] = [];
itemsByCategory: { [categoryTitle: string]: Item[] } = {};
arrItems: Item[] = [];
category: Item | null = null;
item: Item | null = null;
//----------- SERVICES-----------//
categoriesService = inject(CategoriesService);
itemsService = inject(ItemsService);
Object: any;
//----------- NG-ON-INIT -----------//
async ngOnInit() {
// ALL CATEGORIES
this.allCategories = await this.itemsService.getAll();
// ALL ITEMS
this.arrItems = await this.itemsService.getAll();
// CATEGORIES WITH ITEMS
this.arrItems.forEach(item => {
const categoryTitle = item.categoryTitle;
if (!this.itemsByCategory[categoryTitle]) {
this.itemsByCategory[categoryTitle] = [];
}
this.itemsByCategory[categoryTitle].push(item);
});
}
}
<section>
<div>
@for (item of arrItems; track $index) {
<h2>{{ item.categoryTitle }}</h2>
<div>
@for (item of arrItems; track $index) {
<div>
<card-item [item]="item"></card-item>
</div>
}
</div>
}
</div>
</section>
我可以使用控制台在需要时查看项目列表中的对象,这意味着类别标题每个类别显示一次,并且类别中的所有项目(及其功能)都显示在类别下方标题:
Object { Projects: (5) […], Experience: (3) […], Education: (3) […], Certifications: (2) […] }
Certifications: Array [ {…}, {…} ]
0: Object { _id: "66339fa38eaadfa13595bc5b", categoryId: 4, categoryTitle: "Certifications", … }
1: Object { _id: "66339fa38eaadfa13595bc5c", categoryId: 4, categoryTitle: "Certifications", … }
length: 2
<prototype>: Array []
Education: Array(3) [ {…}, {…}, {…} ]
Experience: Array(3) [ {…}, {…}, {…} ]
Projects: Array(5) [ {…}, {…}, {…}, … ]
使用当前的 HTML @发生的情况是,我看到类别标题(和项目)的次数与项目的数量一样多。我需要显示一次类别标题,并且类别中的每个项目只显示一次,而不是像现在一样重复多次。
例如:
认证:
谢谢大家!
最好使用普通的可观察量而不是承诺来保持代码简单,请在下面的代码中注意,我如何将所有代码移动到订阅中,原因是因为订阅下面的代码不会等待订阅完成,所以我们需要将代码移动到订阅中!
在服务中,我刚刚将 API 调用转换为简单的 http get 请求,该请求返回一个可观察值!
getAll() {
return this.httpClient.get<Item[]>(this.baseUrl);
}
在组件中,我们订阅
getAll()
并在订阅块内设置所需的属性!
...
ngOnInit() {
// ALL ITEMS
this.itemsService.getAll().subscribe((res: Item[]) => {
this.arrItems = res;
this.allCategories = res;
// CATEGORIES WITH ITEMS
this.arrItems.forEach(item => {
const categoryTitle = item.categoryTitle;
if (!this.itemsByCategory[categoryTitle]) {
this.itemsByCategory[categoryTitle] = [];
}
this.itemsByCategory[categoryTitle].push(item);
});
...