on
Item availability - part 2
Part 2 of the item-availability
project is now on Github and forked on Stackblitz.
It contains:
- item-ss. An E1 request and response definition for ‘Item Search & Select’ form.
- store update. A new app-state variable for our item selection.
- e1/effects. Logic to map E1’s response to the new app-state variable.
- item-search.component. The ‘Item Search & Select’ page.
- app.routing.module update. Route to the new page.
item-ss
File item-ss.ts
has been added to the /e1
folder with a request class for P40ITM1_W40ITM1A
and interface helpers for the response.
Lets first look at the request class:
export class ItemSSRequest extends FormRequest {
constructor(text: string, item: string) {
super();
this.formName = 'P40ITM1_W40ITM1A';
this.formServiceAction = 'R';
this.maxPageSize = '1000';
this.returnControlIDs = '1[56,50,28,30,23]';
if (text || item) {
this.query = {
condition: [],
autoFind: true,
matchType: 'MATCH_ALL',
autoClear: true,
};
if (text) {
this.query.condition.push({
value: [
{
content: text,
specialValueId: 'LITERAL'
}
],
controlId: '1[56]',
operator: 'STR_START_WITH'
});
}
if (item) {
this.query.condition.push({
value: [
{
content: item,
specialValueId: 'LITERAL'
}
],
controlId: '1[50]',
operator: 'STR_START_WITH'
});
}
}
}
}
We extend FormRequest
with specifics like formName
, the returnControlIDs
we want back and an ad-hoc query for our selection.
To determine the control id’s either use E1’s Item Help
or my preferred method which is to call the form initially without any limitation and use Redux DevTools
browser extension to extract the parameters.
For details on request parameters see Performing AIS Form Service Calls.
The purpose of the response interfaces is to help extracting individual values, like the five grid columns we want to show.
export interface IItemSSRow extends IRow {
sItemMasterSearchText_56: IValue;
sItemNumber_50: IValue;
sItemMasterDescription_28: IValue;
sItemMasterDescriptionLine2_30: IValue;
mnShortItemNo_23: INumber;
}
store update
We have a new items
data definition for the app-state.
export interface IItem {
select: boolean,
text: string;
item: string;
desc: string;
desc2: string;
short: number | string;
}
export interface IAppState {
items: IItem[];
}
We need a new action ItemsAction
to update the items
state.
export enum ActionTypes {
ITEMS = 'ITEMS',
RESET = 'APP_RESET'
}
export namespace AppActions {
export class ResetAction implements Action {
readonly type = ActionTypes.RESET;
}
export class ItemsAction implements Action {
readonly type = ActionTypes.ITEMS;
constructor(public items: IItem[]) { }
}
export type AllActions =
ResetAction |
ItemsAction;
}
And finally we need to update the reducer
with the action.
export function appReducer(state = initialAppState, action: AppActions.AllActions): IAppState {
switch (action.type) {
case ActionTypes.ITEMS:
return Object.assign({}, state, {
items: [...action.items]
});
This is all standard ngrx
stuff. For more details see the ngrx Github page.
e1/effects
The e1/effects
is where we put any E1 response logic. In this case we want to map the returned grid rows to the application’s items
state.
@Effect()
items$ = this.actions$.ofType<E1Actions.FormResponseAction>(E1ActionTypes.FORM_RESPONSE)
.pipe(
map(action => action.payload.formResponse),
filter(formResponse => formResponse[W40ITM1A]),
switchMap((form: IItemSSResponse) => ObservableOf(new AppActions.ItemsAction(
form.fs_P40ITM1_W40ITM1A.data.gridData.rowset.map(r => {
return {
select: false,
text: r.sItemMasterSearchText_56.value,
item: r.sItemNumber_50.value,
desc: r.sItemMasterDescription_28.value,
desc2: r.sItemMasterDescriptionLine2_30.value,
short: r.mnShortItemNo_23.internalValue
}
})
)))
);
This piece of code waits for a response from W40ITM1A
and then grabs its rowset
and maps it into items
for the app-state.
We use the interface helper IItemSSResponse
to extract the fields we want and send them to the store with the AppActions.ItemsAction
action.
item-search.component
Now that the plumbing is done, we can build the page to display the item list. The page uses Angular Material’s Table Component for the display and most of the code is the table’s html
definition.
The only addition is to trigger an E1 request and plug the response to the table.
search() {
this.form.request = new ItemSSRequest(this.text, this.item);
this.e1.call(this.form);
}
done() {/* TODO: Item availability request for selected items */}
ngOnInit() {
this.itemList.sort = this.sort;
this.subscr = this.items.subscribe(items => this.itemList.data = items);
}
ngOnDestroy() {
this.subscr.unsubscribe();
}
constructor(
store: Store<IState>,
private form: FormService,
private e1: E1HelperService
) {
this.status = store.select<string>(s => s.e1.status);
this.items = store.select<IItem[]>(s => s.app.items);
}
We get a this.items
observable variable of items
app-state, subscribe to it and pass the results to the table.
On pressing the search
button an instance of ItemSSRequest
class is created, with the text
and item
parameters. The e1
helper service is then used to submit it to AIS.
app-routing.module update
Finally we need to update our routing module to activate the new page.
const routes: Routes = [
{ path: 'item-search', component: ItemSearchComponent },
{ path: '**', component: ItemSearchComponent }
];
The only thing we do here is to create a item-search
route for later use and default the routing to our new page.