refactor filter models

This commit is contained in:
Dan Percic 2021-08-05 16:47:38 +03:00
parent 3625e29516
commit 4004c4c8f9
7 changed files with 42 additions and 37 deletions

View File

@ -9,4 +9,5 @@ export * from './lib/utils/types/tooltip-positions.type';
export * from './lib/filtering/filter.service';
export * from './lib/filtering/filter-utils';
export * from './lib/filtering/models/filter-group.model';
export * from './lib/filtering/models/nested-filter.model';
export * from './lib/filtering/models/filter.model';

View File

@ -1,7 +1,8 @@
import { FilterModel } from './models/filter.model';
import { NestedFilter } from './models/nested-filter.model';
import { FilterGroup } from './models/filter-group.model';
import { Filter } from './models/filter.model';
export function processFilters(oldFilters: FilterModel[], newFilters: FilterModel[]) {
export function processFilters(oldFilters: NestedFilter[], newFilters: NestedFilter[]) {
copySettings(oldFilters, newFilters);
if (newFilters) {
newFilters.forEach(filter => {
@ -11,33 +12,33 @@ export function processFilters(oldFilters: FilterModel[], newFilters: FilterMode
return newFilters;
}
function copySettings(oldFilters: FilterModel[], newFilters: FilterModel[]) {
function copySettings(oldFilters: NestedFilter[], newFilters: NestedFilter[]) {
if (oldFilters && newFilters) {
for (const oldFilter of oldFilters) {
const newFilter = newFilters.find(f => f.key === oldFilter.key);
if (newFilter) {
newFilter.checked = oldFilter.checked;
newFilter.indeterminate = oldFilter.indeterminate;
if (oldFilter.filters && newFilter.filters) copySettings(oldFilter.filters, newFilter.filters);
if (oldFilter.children && newFilter.children) copySettings(oldFilter.children, newFilter.children);
}
}
}
}
export function handleCheckedValue(filter: FilterModel) {
if (filter.filters && filter.filters.length) {
filter.checked = filter.filters.reduce<boolean>((acc, next) => acc && !!next.checked, true);
export function handleCheckedValue(filter: NestedFilter) {
if (filter.children && filter.children.length) {
filter.checked = filter.children.reduce<boolean>((acc, next) => acc && !!next.checked, true);
if (filter.checked) {
filter.indeterminate = false;
} else {
filter.indeterminate = filter.filters.reduce<boolean>((acc, next) => acc || !!next.checked, false);
filter.indeterminate = filter.children.reduce<boolean>((acc, next) => acc || !!next.checked, false);
}
} else {
filter.indeterminate = false;
}
}
export function checkFilter(entity: any, filters: FilterModel[], validate: Function, validateArgs: any = [], matchAll: boolean = false) {
export function checkFilter(entity: any, filters: NestedFilter[], validate: Function, validateArgs: any = [], matchAll: boolean = false) {
const hasChecked = filters.find(f => f.checked);
if (validateArgs) {
@ -65,7 +66,7 @@ export function checkFilter(entity: any, filters: FilterModel[], validate: Funct
return filterMatched;
}
export const keyChecker = (key: string) => (entity: any, filter: FilterModel) => entity[key] === filter.key;
export const keyChecker = (key: string) => (entity: any, filter: NestedFilter) => entity[key] === filter.key;
export function getFilteredEntities<T>(entities: T[], filters: FilterGroup[]) {
const filteredEntities: T[] = [];
@ -80,3 +81,11 @@ export function getFilteredEntities<T>(entities: T[], filters: FilterGroup[]) {
}
return filteredEntities;
}
export function flatChildren(filters: NestedFilter[]): Filter[] {
return filters.reduce((acc: Filter[], f) => [...acc, ...(f?.children ?? [])], []);
}
export function toFlatFilters(groups: FilterGroup[]): Filter[] {
return groups.reduce((acc: Filter[], f) => [...acc, ...f.filters, ...flatChildren(f.filters)], []);
}

View File

@ -1,9 +1,9 @@
import { Injectable } from '@angular/core';
import { processFilters } from './filter-utils';
import { processFilters, toFlatFilters } from './filter-utils';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators';
import { FilterGroup } from './models/filter-group.model';
import { FilterModel } from './models/filter.model';
import { NestedFilter } from './models/nested-filter.model';
@Injectable()
export class FilterService {
@ -21,7 +21,7 @@ export class FilterService {
private get _showResetFilters$(): Observable<boolean> {
return this.filterGroups$.pipe(
map(all => this._toFlatFilters(all)),
map(toFlatFilters),
map(f => !!f.find(el => el.checked)),
distinctUntilChanged()
);
@ -36,7 +36,7 @@ export class FilterService {
if (!filters) return console.error(`Cannot find filter group "${filterGroupSlug}"`);
let found = filters.find(f => f.key === key);
if (!found) found = filters.map(f => f.filters?.find(ff => ff.key === key))[0];
if (!found) found = filters.map(f => f.children?.find(ff => ff.key === key))[0];
if (!found) return console.error(`Cannot find filter with key "${key}" in group "${filterGroupSlug}"`);
found.checked = !found.checked;
@ -56,7 +56,7 @@ export class FilterService {
return this.filterGroups.find(group => group.slug === slug);
}
getFilterModels$(filterGroupSlug: string): Observable<FilterModel[] | undefined> {
getFilterModels$(filterGroupSlug: string): Observable<NestedFilter[] | undefined> {
return this.getFilterGroup$(filterGroupSlug).pipe(map(f => f?.filters));
}
@ -65,24 +65,14 @@ export class FilterService {
}
reset(): void {
this.filterGroups.forEach(item => {
item.filters.forEach(child => {
child.checked = false;
child.indeterminate = false;
child.filters?.forEach(f => {
f.checked = false;
f.indeterminate = false;
});
this.filterGroups.forEach(group => {
group.filters.forEach(filter => {
filter.checked = false;
filter.indeterminate = false;
filter.children?.forEach(f => (f.checked = false));
});
});
this.refresh();
}
private _toFlatFilters(entities: FilterGroup[]): FilterModel[] {
const flatChildren = (filters: FilterModel[]) =>
(filters ?? []).reduce((acc: FilterModel[], f) => [...acc, ...(f?.filters ?? [])], []);
return entities.reduce((acc: FilterModel[], f) => [...acc, ...f.filters, ...flatChildren(f.filters)], []);
}
}

View File

@ -1,8 +1,8 @@
import { FilterModel } from './filter.model';
import { NestedFilter } from './nested-filter.model';
import { TemplateRef } from '@angular/core';
export interface FilterGroup {
filters: FilterModel[];
filters: NestedFilter[];
readonly slug: string;
readonly label?: string;
readonly icon?: string;

View File

@ -1,13 +1,10 @@
export interface FilterModel {
export interface Filter {
readonly key: string;
checked?: boolean;
indeterminate?: boolean;
expanded?: boolean;
matches?: number;
readonly label?: string;
readonly label: string;
readonly icon?: string;
readonly topLevelFilter?: boolean;
readonly filters?: FilterModel[];
readonly checker?: (obj?: unknown) => boolean;
readonly required?: boolean;
}

View File

@ -0,0 +1,7 @@
import { Filter } from './filter.model';
export interface NestedFilter extends Filter {
expanded?: boolean;
indeterminate?: boolean;
readonly children?: Filter[];
}

View File

@ -6,6 +6,7 @@
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"strict": true,
"types": [],
"lib": ["dom", "es2018"]
},