com.sabre.redapp.example3.web.persistence Sample
Persistence sample shows how to handle shared state in Red App using Redux.
export class Main extends Module {
localStore: LocalStore;
init(): void {
super.init();
const xp = getService(ExtensionPointService);
const sidepanelConfig = new RedAppSidePanelConfig([ // (1)
new RedAppSidePanelButton('Open persist view', 'btn btn-secondary side-panel-button redapp-web-persistence', () => this.showView()),
]);
xp.addConfig('redAppSidePanel', sidepanelConfig);
registerService(PRCustomCommandHandler); // (2)
registerService(LocalStoreHelperService);
this.localStore = new LocalStore();
getService(PRCustomCommandHandler).setLocalStore(this.localStore); // (3)
const button: StaticButton = new StaticButton(this.localStore.store); // (4)
xp.addConfig('novice-buttons', new WidgetXPConfig(button, -1000));
}
private showView(): void {
let addRemarkModalOptions = {
title: 'Modal with session persistence',
actions: [{
className: 'app.common.views.Button',
caption: 'OK',
actionName: 'cancel',
type: 'secondary'
}]
};
getService(LayerService).showInModal(
new BasicView({ model: new BasicModel(this.localStore) }), addRemarkModalOptions, { display: 'areaView' }
);
}
}
-
Starting with Main class we create button in Workflows sidepanel that allows us to show modal window.
-
Then we register custom command handler service.
-
Created store was send passed to command handler, so it can be used in the service.
-
Same way we send it to StaticButton and futher to React component so it can be used there
export interface Data { // (1)
messageAreaA: string;
messageAreaB: string;
messageAreaC: string;
messageAreaD: string;
messageAreaE: string;
messageAreaF: string;
}
const defaultState: Data = { // (2)
messageAreaA: 'Area A',
messageAreaB: 'Area B',
messageAreaC: 'Area C',
messageAreaD: 'Area D',
messageAreaE: 'Area E',
messageAreaF: 'Area F'
}
function reducer(state: Data = defaultState, action) {
const newState = {};
const currentMessageName = getService(LocalStoreHelperService).getCurrentMessageName();
newState[currentMessageName] = action.newVal;
switch (action.type) {
case 'CHANGE_MSG':
return {
...state,
...newState
};
default:
return state
}
}
export class LocalStore {
public store = createStore(reducer); // (3)
getData(): Data {
return this.store.getState();
}
getCurrentAreaMessage(): string { // (4)
const currentMessageName = getService(LocalStoreHelperService).getCurrentMessageName();
return this.store.getState()[currentMessageName];
}
setMessage(newVal: string) {
const action = { type: "CHANGE_MSG", newVal: newVal };
this.store.dispatch(action);
}
}
-
Since we use TypeScript we need interface to strong-type the data keept in the store
-
Redux reducer - simple function that changes the state of redapp based on send actions
-
Creating redux store
-
Method that can be used to create action and dispatch it to store. It’s a good practice to create actions in one place.
export class BasicModel extends AbstractModel {
text: string;
localStore: LocalStore;
constructor(localStore: LocalStore) {
super();
this.localStore = localStore;
console.log("Store state durig initailization:", localStore.store.getState());
this.text = localStore.getCurrentAreaMessage(); // (1)
}
getText(): string {
return this.text;
}
setText(text: string): void {
this.text = text;
this.localStore.setMessage(text); // (2)
}
}
-
Model’s data will be based on one kept in redux store
-
Changing the data is done using the
setMessage
function inLocalStore
, the one that creates actions and sends it to the reducer using thedispatch
function.
export class BasicView extends AbstractView<BasicModel> {
constructor(options?: AbstractViewOptions) {
super(options);
super.addDomEvents({
'keyup .change-message-ra': '_saveVal', // (1)
});
}
_saveVal() {
const x: string = super.$('.brand-input').val();
super.getModel().setText(x);
}
}
-
After adding each new char in view’s text field, the text field in model is updated. So, after each key-stroke in text field there is a new action created and redux store state updates.
export class PRCustomCommandHandler extends CustomCommandHandler {
localStore: LocalStore;
static SERVICE_NAME =
"com-sabre-redapp-example3-web-persistence-web-module-PRCustomCommandHandler";
onCommandSend(rq: CustomCommandRq): Promise<CustomCommandRs> {
return new Promise<CustomCommandRs>((resolve, reject) => {
const areaService: IAreaService = getService(IAreaService);
areaService.showBanner('Info', 'Message from redux: ' + this.localStore.getCurrentAreaMessage()); // (1)
resolve();
});
}
setLocalStore(store: LocalStore): void {
this.localStore = store;
console.log("Local store set to ", store);
}
}
-
Using state from the store is pretty straight-forward, use
getState()
or dedicated function on store to access needed state.
Working sample can be found in samples directory under com.sabre.redapp.example3.web.persistence name.