在服务中合并来自两个来源的数据的一种好方法是什么?

时间:2019-09-09 17:25:46

标签: angular rxjs

因此,我遇到了这个问题,我一直想把头缠起来:我有这一系列的边栏项目,需要从两个来源合并。第一个来源将在前端代码库中,并且与项目的视觉方面有关:图标类,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;
           }
       });
    }
}

在使用组件中的该服务,订阅结果并注意到各种问题之后,我决定尝试异步等待,这样我就知道组件中的所有信息都是立即可用的。这是一个好选择吗?

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

  • 我正在使用一条指令(附加到某处的按钮上),将这些项目标记为已完成,反之亦然。合并的信息需要在这里可用。我选择一个指令是因为我在多个地方都需要相同的逻辑;
  • 在服务中进行标记时,我需要合并的信息,因为在向后端发送请求时,我需要在商品上显示ID;
  • 在组件本身中,我根据url标识当前项目(因为刷新后,通过导航到某个项目(单击该项目)而传播的参数将不可用)。 / li>

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

最新编辑:据我所知,我需要这些物品的某种形式的单一事实来源,以便它们根据标记/未标记来更新其状态。到目前为止,仅使用async + await即可。

1 个答案:

答案 0 :(得分:-1)

我建议在这里使用Observables,async / await也正在等待,但是使您的代码可读。

此外,您还可以在代码中制作作为地图保存在本地的项目,这样读取速度更快,并且可以使用键/值对作为项目名称,将值作为项目值来获取它们。 {{name: {item} }}

您可以使用异步管道将可观察对象直接绑定到模板,如下所示

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;
  })
}