AutoComplete for suggestions with array of type number
Goal: Add AutoComplete Number
Add an AutoComplete for suggestions with array of type number as a search criteria input field for your search page.
Please replace all occurences of exampleNumberArray with the actual name in the following code snippets |
1. Parameters
Please define the member for your <%= featurePropertyName %>SearchCriteriasSchema here.
Adapt in File: <feature>-search.parameters.ts
exampleNumberArray: z
.union([z.string(), z.array(z.string())])
.transform((v: string | string[] | undefined): string[] | undefined =>
v instanceof Array || !v
? (v as string[] | undefined)
: ([v] as string[]),
)
.transform((v: string[] | undefined) => v?.map((e) => Number(e)))
.optional(),
2. State & viewmodel
Add additional array member for the AutoComplete suggestions in your state and viewmodel:
Adapt in Files: <feature>-search.viewmodel.ts
and <feature>-search.state.ts
...
exampleNumberArrayOptions: number[]
...
3. Actions
Create following actions to handle the events regarding AutoComplete:
Adapt in File: <feature>-search.actions.ts
...
events: {
'exampleNumberArray data text entered': props<{ exampleNumberArrayInputValue: number }>(),
'exampleNumberArray data received ': props<{ exampleNumberArrayOptions: number[] }>(),
'exampleNumberArray data loading failed': emptyProps(),
'exampleNumberArray selected': props<{ selectedexampleNumberArrayValue: number }>(),
'exampleNumberArray unselected': props<{ unSelectedexampleNumberArrayValue: number }>(),
},
...
4. HTML
Add the following code to your formGroup in the html file:
Adapt in File: <feature>-search.component.html
<span class="p-float-label">
<p-autoComplete
id="exampleNumberArray"
formControlName="exampleNumberArray"
(completeMethod)="searchexampleNumberArrayData($event)"
[optionLabel]="optionLabelTransformer" <-- NECESSARY FOR PROPERPLY HANDLING ITEMS OF TYPE NUMBER
[suggestions]="vm?.exampleNumberArrayOptions ?? []"
[forceSelection]="true"
[multiple]="true" <-- ONLY NECESSARY IF MULTIPLE VALUES CAN BE SELECTED
[showEmptyMessage]="true"
[emptyMessage]="
vm?.exampleNumberArrayOptions?.length === 0
? ('YOUR_PRODUCT_SEARCH.CRITERIA.EXAMPLE_ID_NOT_FOUND' | translate)
: ''
"
(onSelect)="selectexampleNumberArrayValue($event)"
(onUnselect)="unSelectexampleNumberArrayValue($event)"
>
</p-autoComplete>
<label for="exampleNumberArray">{{
'YOUR_PRODUCT_SEARCH.CRITERIA.ID' | translate
}}</label>
</span>
5. Component
Add the respective methods to handle the different events and in addition a transformer method to correctly deal with the number type it needs to convert the number to a string:
Adapt in File: <feature>-search.component.ts
...
optionLabelTransformer(item: number): string {
return item?.toString();
}
searchexampleNumberArrayData(event: AutoCompleteCompleteEvent) {
this.store.dispatch(
<feature>SearchActions.exampleNumberArrayDataTextEntered({
exampleNumberArrayInputValue: event.query,
}),
);
}
selectexampleNumberArrayValue(event: AutoCompleteSelectEvent) {
this.store.dispatch(
<feature>SearchActions.exampleNumberArraySuggestionSelected({
selectedexampleNumberArrayValue: event.value,
}),
);
}
unSelectexampleNumberArrayValue(event: AutoCompleteUnselectEvent) {
this.store.dispatch(
<feature>SearchActions.exampleNumberArraySuggestionUnselected({
unSelectedexampleNumberArrayValue: event.value,
}),
);
}
...
6. Reducers
In the reducers file you need to define the functions:
Adapt in File: <feature>-search.reducers.ts
...
on(
<%= featureClassName %>SearchActions.exampleNumberArrayDataReceived,
(state: <%= featureClassName %>SearchState, { exampleNumberArrayOptions }): <%= featureClassName %>SearchState => ({
...state,
exampleNumberArrayOptions: exampleNumberArrayOptions,
}),
),
on(
<%= featureClassName %>SearchActions.exampleNumberArrayDataLoadingFailed,
(state: <%= featureClassName %>SearchState): <%= featureClassName %>SearchState => ({
...state,
exampleNumberArrayOptions: [],
}),
),
on(
<%= featureClassName %>SearchActions.exampleNumberArraySuggestionSelected,
(
state: <%= featureClassName %>SearchState,
{ selectedexampleNumberArrayValue },
): <%= featureClassName %>SearchState => {
const isValuePresent =
state.exampleNumberArraySelectedValues.includes(selectedexampleNumberArrayValue);
return {
...state,
exampleNumberArraySelectedValues: isValuePresent
? state.exampleNumberArraySelectedValues
: [...state.exampleNumberArraySelectedValues, selectedexampleNumberArrayValue],
exampleNumberArrayOptions: [],
};
},
),
on(
<%= featureClassName %>SearchActions.exampleNumberArraySuggestionUnselected,
(
state: <%= featureClassName %>SearchState,
{ unSelectedexampleNumberArrayValue },
): <%= featureClassName %>SearchState => ({
...state,
exampleNumberArraySelectedValues: state.exampleNumberArraySelectedValues.filter(
(exampleNumberArray) => exampleNumberArray !== unSelectedexampleNumberArrayValue,
),
exampleNumberArrayOptions: [],
}),
),
...
7. Selectors
Add the missing selectors:
Adapt in File: <feature>-search.selectors.ts
...
export const select<%= featureClassName %>SearchViewModel = createSelector(
...
<feature>SearchSelectors.
selectExampleNumberArrayOptions,
...
(
...
exampleNumberArrayOptions,
...
): <%= featureClassName %>SearchViewModel => ({
...
exampleNumberArrayOptions,
...
}),
);
...
8. Effects
Create the effect for getting the suggestions
Adapt in File: <feature>-search.effects.ts
...
searchexampleNumberArray$ = createEffect(() =>
this.actions$.pipe(
ofType(<%= featureClassName %>SearchActions.exampleNumberArrayDataTextEntered),
mergeMap((action) => {
return this.<feature>Service
.searchexampleNumberArray(action.exampleNumberArrayInputText)
.pipe(
map((response) =>
<%= featureClassName %>SearchActions.exampleNumberArrayDataReceived({
exampleNumberArrayOptions: response.exampleNumberArray, <-- NAME OF THE MEMBER WHICH IS DEFINED IN THE RESPONSE OBJECT
}),
),
catchError(() =>
of<%= featureClassName %>SearchActions.exampleNumberArrayDataLoadingFailed()),
),
);
}),
),
);
...
Don’t forget to add the translations to your de.json and en.json. |