angular - 在服务中组合来自两个来源的数据的好方法是什么?
问题描述
所以我遇到了这个问题,我一直试图解决这个问题:我有这个侧边栏项目数组,我需要从两个来源合并。第一个来源将在前端代码库中,它与项目的视觉方面有关:图标类、url 等,我们将使用前端代码库进行维护。第二个来源是数据库,因为我需要在其中保留一些信息以提供一种功能,其中任何一项都可以标记为已完成,并且它们的状态应该保持不变。
这些项目如下所示:
export interface Item {
id?: number;
name: string;
label: string;
completed?: boolean;
iconClass: string;
url: string;
}
我在前端维护标签、iconClass 和 url,并从数据库中获取 id 并完成,然后按名称“加入”它们,这两个源中都存在。
这是我的服务片段:
export class SidebarService {
someNecessaryId: number;
// I keep the front-end related items here for the moment
items: Item[] = [...];
constructor(
private http: HttpClient
) { }
async init() {
const url = `${baseUrl}/${this.someNecessaryId}/sidebar-items`;
const itemsDb = await this.http.get(url).toPromise();
if (itemsDb instanceof Array && itemsDb.length) {
// Here I basically merge the two sources together
this.items = this.items.map(item => {
const found = itemsDb.filter(itemDb => itemDb.name === item.name)[0];
return {...item, ...found};
});
}
}
mark(item: Item) {
const actualItem = this.items.filter(fItem => fItem.name === item.name)[0];
const url = `${baseUrl}/${this.someNecessaryId}/sidebar-items/${item.id}/mark`;
this.http.post(url, item)
.subscribe(res => {
if (res instanceof Item) {
actualItem.completed = res.completed;
}
});
}
}
在组件中使用此服务、订阅结果并注意到各种问题后,我决定尝试 async await,以便我知道所有信息都可以立即在组件中使用。这是一个不错的选择吗?
编辑:我可能遗漏了一些重要的细节。为了描绘更大的图景:
- 我正在使用一个指令(附加到某处的按钮)将这些项目标记为已完成,反之亦然。合并的信息需要在此处可用。我选择了一个指令,因为我在多个地方都需要同样的逻辑;
- 在服务中标记时我需要合并的信息,因为在将请求发送到后端时我需要在项目上显示 id;
- 在组件本身中,我根据 url 识别当前项目(因为在刷新时,通过导航到项目传播的参数 - 单击它 - 将不可用)。
到目前为止,我看到的唯一可行的选择是使用 APP_INITIALIZER 来确定所有这些地方的全部信息都可用。
后期编辑:据我所知,我需要为这些项目提供某种形式的单一事实来源,以便他们根据标记/取消标记更新它们的状态。到目前为止,只有使用 async + await 才能做到这一点。
解决方案
我建议在这里使用 Observables,async/await 也在等待,但让你的代码可读。
此外,您还可以在代码中将项目作为地图保存在本地,这样读取速度会更快,并且您可以使用键/值对作为项目名称和值作为项目值来获取它们。{ {name: {item} }
}
您可以使用异步管道直接将 observable 绑定到模板,如下所示
export class SidebarService {
someNecessaryId: number;
// I keep the front-end related items here for the moment
itemsMap: { [key: tsring]: Item } = {}; // keep an Hashmap or object dictionary for faster reads
items$: Observable<Item[]>;
constructor(
private http: HttpClient
) { }
async init() {
const url = `${baseUrl}/${this.someNecessaryId}/sidebar-items`;
this.items$ = this.http.get(url)
.pipe(
map(response => response.map(item => ({
...item, ...(this.itemsMap[item.name] || {})
})))
);
}
getItems () {
return this.items$;
}
}
从模板
<div *ngFor="let item of items$ | async">
<!-- do something with item in this for loop -->
从(指令/组件).ts
items = [];
constructor (private service: SidebarService) {
this.service.init();
}
getData() {
this.service.getItems().subscribe(items => {
this.items = items;
})
}
推荐阅读
- list - nextflow (groovy) 检查频道列表中的项目
- c# - ElasticSearch 中的分层搜索
- python - 导入ValueError异常时导入错误
- reactjs - 在反应 js 中显示相同的数据,如果条件不工作或工作但映射函数获取所有值而不进行排序
- python - 我想通过使用 lambda 更改此 def
- python - python如何从main调用函数
- c# - 如何在 C# 中为 GC 正确固定对象以防止 AccessViolationException?
- php - 会话不会在 laravel 5.6 中刷新/保留
- nuxt.js - Nuxt 使用 vuex 和多语言站点生成
- tensorflow - 如何使用 tf.strategy 修改 Keras CycleGAN 示例代码以在 GPU 上并行运行