diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/typeahead.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/typeahead.util.ts new file mode 100644 index 0000000000..be89c4a295 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/typeahead.util.ts @@ -0,0 +1,43 @@ +import { ABP, ExtensionPropertyUiLookupDto, RestService } from '@abp/ng.core'; +import { Observable, of } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { ePropType } from '../enums/props.enum'; +import { PropCallback } from '../models/props'; + +export function createTypeaheadOptions( + lookup: ExtensionPropertyUiLookupDto, +): PropCallback[]>> { + return (data, searchText) => + searchText + ? data + .getInjected(RestService) + .request( + { + method: 'GET', + url: lookup.url, + params: { + [lookup.filterParamName]: searchText, + }, + }, + { apiName: 'Default' }, + ) + .pipe( + map(response => { + const list = response[lookup.resultListPropertyName]; + const mapToOption = (item: any) => ({ + key: item[lookup.displayPropertyName], + value: item[lookup.valuePropertyName], + }); + return list.map(mapToOption); + }), + ) + : of([]); +} + +export function getTypeaheadType(lookup: ExtensionPropertyUiLookupDto, name: string) { + return Boolean(lookup.url) + ? ePropType.Typeahead + : name.endsWith('_Text') + ? ePropType.Hidden + : undefined; +} diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/tests/typeahead.util.spec.ts b/npm/ng-packs/packages/theme-shared/extensions/src/tests/typeahead.util.spec.ts new file mode 100644 index 0000000000..479b1d4fcf --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/extensions/src/tests/typeahead.util.spec.ts @@ -0,0 +1,72 @@ +import { ExtensionPropertyUiLookupDto } from '@abp/ng.core'; +import { of } from 'rxjs'; +import { createTypeaheadOptions } from '../lib/utils/typeahead.util'; + +const lookup: ExtensionPropertyUiLookupDto = { + url: 'url', + resultListPropertyName: 'list', + displayPropertyName: 'text', + valuePropertyName: 'id', + filterParamName: 'filter', +}; + +describe('Typeahead Utils', () => { + describe('#createTypeaheadOptions', () => { + it('should return observable empty array when search text does not exist', async () => { + const list = await createTypeaheadOptions(null)(null, null).toPromise(); + expect(list).toEqual([]); + }); + + it('should call request method of RestService with lookup url, filter param and search text', async () => { + const data = createData([]); + const service = data.getInjected(); + await createTypeaheadOptions(lookup)(data, 'x').toPromise(); + expect(service.request).toHaveBeenCalledTimes(1); + expect(service.request).toHaveBeenCalledWith( + { + method: 'GET', + url: 'url', + params: { + filter: 'x', + }, + }, + { apiName: 'Default' }, + ); + }); + + it('should return options based on given lookup data', async () => { + const data = createData([ + { + text: 'foo', + id: 'bar', + }, + { + text: 'baz', + id: 'qux', + }, + ]); + + const options = await createTypeaheadOptions(lookup)(data, 'x').toPromise(); + expect(options).toEqual([ + { + key: 'foo', + value: 'bar', + }, + { + key: 'baz', + value: 'qux', + }, + ]); + }); + }); +}); + +function createData(list: { text: string; id: string }[]): any { + const service = { request: jest.fn(() => of({ list })) }; + + return { + getInjected: () => service, + index: 0, + record: null, + }; +}