diff --git a/packages/dbx-form/src/lib/formly/field/selection/pickable/pickable.field.ts b/packages/dbx-form/src/lib/formly/field/selection/pickable/pickable.field.ts index a40e9d302..f5808e8a7 100644 --- a/packages/dbx-form/src/lib/formly/field/selection/pickable/pickable.field.ts +++ b/packages/dbx-form/src/lib/formly/field/selection/pickable/pickable.field.ts @@ -1,17 +1,21 @@ import { FormlyFieldConfig } from '@ngx-formly/core'; -import { Maybe } from '@dereekb/util'; +import { Maybe, searchStringFilterFunction, SearchStringFilterFunction, caseInsensitiveFilterByIndexOfDecisionFactory } from '@dereekb/util'; import { Observable, of } from 'rxjs'; import { LabeledFieldConfig, formlyField, propsForFieldConfig } from '../../field'; import { PickableValueFieldDisplayValue } from './pickable'; import { PickableItemFieldItem, PickableValueFieldsFieldProps } from './pickable.field.directive'; export { PickableItemFieldItem }; +export const filterPickableItemFieldValuesByLabelFilterFunction: SearchStringFilterFunction> = searchStringFilterFunction({ + readStrings: (x) => [x.label], + decisionFactory: caseInsensitiveFilterByIndexOfDecisionFactory +}); + export function filterPickableItemFieldValuesByLabel(filterText: Maybe, values: PickableValueFieldDisplayValue[]): Observable { let filteredValues: PickableValueFieldDisplayValue[]; if (filterText) { - const searchString = filterText.toLocaleLowerCase(); - filteredValues = values.filter((x) => x.label.toLocaleLowerCase().indexOf(searchString) !== -1); + filteredValues = filterPickableItemFieldValuesByLabelFilterFunction(filterText, values); } else { filteredValues = values; } diff --git a/packages/util/src/lib/array/array.string.spec.ts b/packages/util/src/lib/array/array.string.spec.ts index 977477916..499e71ea6 100644 --- a/packages/util/src/lib/array/array.string.spec.ts +++ b/packages/util/src/lib/array/array.string.spec.ts @@ -1,4 +1,4 @@ -import { containsAllStringsAnyCase, containsAnyStringAnyCase, containsStringAnyCase, findUniqueCaseInsensitiveStrings, findUniqueTransform, TransformSingleStringFunction } from './array.string'; +import { containsAllStringsAnyCase, containsAnyStringAnyCase, containsStringAnyCase, findUniqueCaseInsensitiveStrings, findUniqueTransform, searchStringFilterFunction, TransformSingleStringFunction, caseInsensitiveFilterByIndexOfDecisionFactory } from './array.string'; describe('findUniqueCaseInsensitiveStrings', () => { it('should return only the strings that are unique from the array.', () => { @@ -137,3 +137,22 @@ describe('findUniqueTransform', () => { }); }); }); + +describe('searchStringFilterFunction', () => { + describe('function', () => { + const filterFunction = searchStringFilterFunction({ + readStrings: (x: string) => [x], + decisionFactory: caseInsensitiveFilterByIndexOfDecisionFactory + }); + + it('should return the values that match the filter', () => { + const filterText = 'a'; + const values = ['a', 'AA', 'b']; + + const result = filterFunction(filterText, values); + expect(result).toContain('a'); + expect(result).toContain('AA'); + expect(result).not.toContain('b'); + }); + }); +}); diff --git a/packages/util/src/lib/array/array.string.ts b/packages/util/src/lib/array/array.string.ts index 2d63e32a6..ebc99e98a 100644 --- a/packages/util/src/lib/array/array.string.ts +++ b/packages/util/src/lib/array/array.string.ts @@ -1,10 +1,10 @@ import { flattenArray } from './array'; import { unique, findUnique } from './array.unique'; -import { ReadKeyFunction } from '../key'; +import { ReadKeyFunction, ReadKeysFunction } from '../key'; import { caseInsensitiveString } from '../string'; import { containsAllValues, containsAnyValue, hasDifferentValues } from '../set/set'; import { mapIterable } from '../iterable/iterable.map'; -import { mapArrayFunction, MapFunction, mapIdentityFunction } from '../value'; +import { DecisionFunction, DecisionFunctionFactory, mapArrayFunction, MapFunction, mapIdentityFunction } from '../value'; export function hasDifferentStringsNoCase(a: string[], b: string[]): boolean { return hasDifferentValues(a.map(caseInsensitiveString), b.map(caseInsensitiveString)); @@ -97,3 +97,33 @@ export function findUniqueTransform(config: FindUniqueStringsTransformConfig): F return (input: string[]) => Array.from(new Set(transform(input))); } } + +// MARK: Search Strings +/** + * Filters values by the input filter text. + */ +export type SearchStringFilterFunction = (filterText: string, values: T[]) => T[]; + +export interface SearchStringFilterConfig { + readStrings: ReadKeysFunction; + decisionFactory: DecisionFunctionFactory; +} + +export function searchStringFilterFunction(config: SearchStringFilterConfig): SearchStringFilterFunction { + const { readStrings, decisionFactory } = config; + + return (filterText: string, values: T[]) => { + const decision = decisionFactory(filterText); + + return values.filter((value: T) => { + const strings = readStrings(value); + const keep = strings.findIndex(decision) !== -1; + return keep; + }); + }; +} + +export const caseInsensitiveFilterByIndexOfDecisionFactory: DecisionFunctionFactory = (filterText: string) => { + const searchString = filterText.toLocaleLowerCase(); + return (string: string) => string.toLocaleLowerCase().indexOf(searchString) !== -1; +}; diff --git a/packages/util/src/lib/value/decision.ts b/packages/util/src/lib/value/decision.ts new file mode 100644 index 000000000..4ab4e0df8 --- /dev/null +++ b/packages/util/src/lib/value/decision.ts @@ -0,0 +1,10 @@ +import { FactoryWithRequiredInput } from '../getter/getter'; +import { MapFunction, AsyncMapFunction } from './map'; + +/** + * A map function that derives a boolean from the input. + */ +export type DecisionFunction = MapFunction; +export type AsyncDecisionFunction = AsyncMapFunction>; + +export type DecisionFunctionFactory = FactoryWithRequiredInput, C>; diff --git a/packages/util/src/lib/value/index.ts b/packages/util/src/lib/value/index.ts index a01447b60..6c06d36ac 100644 --- a/packages/util/src/lib/value/index.ts +++ b/packages/util/src/lib/value/index.ts @@ -1,4 +1,5 @@ export * from './build'; +export * from './decision'; export * from './equal'; export * from './map'; export * from './maybe.type'; diff --git a/packages/util/src/lib/value/map.ts b/packages/util/src/lib/value/map.ts index d10fa8c1f..e96183e64 100644 --- a/packages/util/src/lib/value/map.ts +++ b/packages/util/src/lib/value/map.ts @@ -86,10 +86,3 @@ export function mapFunctionOutput(output: O, inpu } }); } - -// MARK: MapTypes -/** - * A map function that derives a boolean from the input. - */ -export type DecisionFunction = MapFunction; -export type AsyncDecisionFunction = AsyncMapFunction>; diff --git a/setup/templates/components/app/project.json b/setup/templates/components/app/project.json index dc04afa78..08db49f8e 100644 --- a/setup/templates/components/app/project.json +++ b/setup/templates/components/app/project.json @@ -1,7 +1,7 @@ { "projectType": "library", "sourceRoot": "ANGULAR_COMPONENTS_FOLDER/src", - "prefix": "ANGULAR_APP_PREFIX", + "prefix": "APP_CODE_PREFIX_LOWER", "targets": { "build": { "executor": "@nrwl/workspace:run-commands",