首页 > 解决方案 > 在服务中组合来自两个来源的数据的好方法是什么?

问题描述

所以我遇到了这个问题,我一直试图解决这个问题:我有这个侧边栏项目数组,我需要从两个来源合并。第一个来源将在前端代码库中,它与项目的视觉方面有关:图标类、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,以便我知道所有信息都可以立即在组件中使用。这是一个不错的选择吗?

编辑:我可能遗漏了一些重要的细节。为了描绘更大的图景:

到目前为止,我看到的唯一可行的选择是使用 APP_INITIALIZER 来确定所有这些地方的全部信息都可用。

后期编辑:据我所知,我需要为这些项目提供某种形式的单一事实来源,以便他们根据标记/取消标记更新它们的状态。到目前为止,只有使用 async + await 才能做到这一点。

标签: angularrxjs

解决方案


我建议在这里使用 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;
  })
}


推荐阅读