Item availability - part 2

Part 2 of the item-availability project is now on Github and forked on Stackblitz.

It contains:

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.