У меня есть угловое приложение, которое использует NGRX в качестве хранилища состояний для данных, поступающих из API.
Первичные данные в приложении - это набор инвентарных предметов.Каждый элемент имеет свойства, связанные с дочерними коллекциями.(т. е. factoryId привязан к коллекциям производителей и т. д.) Я использую ngrx-entity, чтобы иметь возможность индексировать коллекции.
Я хочу отобразить эти данные в сетке на экране вденормализованный способ (отображать имя производителя вместо идентификатора), а затем разрешить им сортировать по любому из этих столбцов.
Хитрость в том, что мне нужно отсортировать данные, находящиеся в дочерней коллекции, иэта дочерняя коллекция сама по себе является наблюдаемым потоком.Единственная «подписка» во всем этом процессе заключается в разметке HTML с «асинхронным» каналом - и я планирую сохранить его таким образом.
Я хочу иметь возможность применять поле сортировки и направление сортировкидинамически, но я не совсем уверен, как это сделать эффективно.Я создал этот пример stackblitz о том, как он работает сейчас.Однако в примере показаны только 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('--------------------');
});