RxJs / Redux / Angular-来自多个可观察流的动态排序功能

时间:2018-12-20 22:55:57

标签: angular sorting rxjs ngrx ngrx-entity

我有一个角度应用程序,它使用NGRX作为来自API的数据的状态存储。

应用程序中的主要数据是库存物品的集合。每个项目都具有键入子集合的属性。 (例如,makerId指向制造商的集合等)。我正在使用ngrx-entity以便能够对集合进行索引。

我想以非规范化方式在屏幕上的网格中显示此数据(显示制造商名称而不是ID),然后允许它们按这些列中的任何一个进行排序。

这里的窍门是,我需要按子集合中的数据进行排序,并且子集合本身是可观察的流。在整个过程中,唯一的“订阅”是带有“异步”管道的HTML标记-我计划保持这种方式。

我希望能够动态地应用排序字段和排序方向,但是我不确定如何有效地进行排序。我已经stackblitz example创建了我现在的工作方式。但是,该示例仅显示了2个子字段,我还有另外六个字段可以排序。代码可能会变得很凌乱。

在某些时候,我还将为此添加某种过滤。

我已经考虑过修改API以返回非规范化的数据,但这似乎不太理想,因为存在数据完整性问题。

这是目前堆栈闪电的代码。我正在寻找一些反馈来改善这一点。

import { of, BehaviorSubject, timer } from 'rxjs'; 
import { map, combineLatest, switchMap } from 'rxjs/operators';

const manufacturers = {
  1: { id: 1, name: 'Acme' },
  2: { id: 2, name: 'Swift' },
  3: { id: 3, name: 'Baker' }
};

const styles = {
  21: { id: 21, code: 'Bridgeport' },
  22: { id: 22, code: 'Summit' },
  23: { id: 23, code: 'Anderson' },
  24: { id: 24, code: 'Saturn' }
};

const couplerTypes = {
  1: { id: 1, name: 'Barringer' },
  2: { id: 2, name: 'Waldorf' }
};

const inventory = [
  { id: 123, manufacturerId: 1, styleId: 21, couplerTypeId: 1},
  { id: 124, manufacturerId: 2, styleId: 21, couplerTypeId: 1},
  { id: 125, manufacturerId: 1, styleId: 23, couplerTypeId: 2},
  { id: 126, manufacturerId: 3, styleId: 24, couplerTypeId: 2},
  { id: 127, manufacturerId: 3, styleId: 22, couplerTypeId: 1},
  { id: 128, manufacturerId: 1, styleId: 22, couplerTypeId: 2},
  { id: 129, manufacturerId: 3, styleId: 24, couplerTypeId: 2},
  { id: 130, manufacturerId: 2, styleId: 21, couplerTypeId: 1},
  { id: 131, manufacturerId: 2, styleId: 21, couplerTypeId: 1},
  { id: 132, manufacturerId: 1, styleId: 24, couplerTypeId: 2},
]

// Assume these four collections are coming from an NGRX store
const manufacturers$ = of(manufacturers);
const styles$ = of(styles);
const couplerTypes$ = of(couplerTypes);
const inventory$ = of(inventory);

// Sort functions
const sortAscending = (one, two) => (one > two ? -1 : 1);
const sortDescending = (one, two) => (one > two ? 1 : -1);

// Start with sort descending
const sortDirection$ = new BehaviorSubject<any>(sortDescending);

// An observable of a function that sorts by manufacturer name combined with the sort direction
const manufacturersSort$ = manufacturers$.pipe(
  combineLatest(sortDirection$),
  map(([manufacturers, sortDirection]) => {
    return (one, two) => sortDirection(
      manufacturers[one.manufacturerId].name,
      manufacturers[two.manufacturerId].name);
  }));

// An observable of a function that sorts by style code combined with the sort direction
const stylesSort$ = styles$.pipe(
  combineLatest(sortDirection$),
  map(([styles, sortDirection]) => {
    return (one, two) => sortDirection(
      styles[one.styleId].code,
      styles[two.styleId].code);
  }));

// A stream of a stream of sort functions
const sortFunction$ = new BehaviorSubject<any>(manufacturersSort$);

// The combination of the inventory and the sort function
const sortedItems$ = sortFunction$.pipe(
  switchMap(innersort$ => innersort$.pipe(
    combineLatest(inventory$),
    switchMap(([innersort, items]) => {
      return of(items.sort(innersort));
    }),
  ))
)

// SHow me the output
timer(1000).subscribe(() => {
  sortDirection$.next(sortAscending);
  timer(1000).subscribe(() => {
    sortFunction$.next(stylesSort$);
    timer(1000).subscribe(() => {
      sortDirection$.next(sortDescending);
    });
  });
});

sortedItems$.subscribe(items => {
  items.map(item =>console.log(`id: ${item.id}, manufacturerId: ${item.manufacturerId}, styleId: ${item.styleId}, couplerTypeId: ${item.couplerTypeId}`));
  console.log('--------------------');
});

0 个答案:

没有答案