Use case: Displaying 2 Form Engines using the same data from 1 activity but load 2 different UI Models. eg: Loading 1 fully CosmoClaims form and 1 CosmoClaimsMetadata form these 2 Forms using the same data but it has different UI Model.
Known Issue: Rendering 2 Form Engines with FormEngineViews.FormEngine doesn’t work → the 1st UI Model loaded will be used in both Form Engine.
Solution: Create 2 containers:
- 1 return FormEngineViews.FormEngine (default wrapper in bap-client for form-engine)
- the other one using your own connected Form Engine which load the 2nd UI Model.
Your custom connected form engine function looks like this:
type StateProps2 = Partial<DefaultStateProps>;
interface OwnProps2 extends View, Partial<Config> {
readonly activity: Activity;
}
const FormEngineView2 = connect<StateProps2, DefaultDispatchProps, OwnProps2, object>(
function mapStateToProps(state: object, ownProps: OwnProps2) {
const dataHolder = ActivitySelectors.dataHolderByDescriptor(
ownProps.activity.id,
ownProps.activity.descriptor)(state);
const document = dataHolder
&& dataHolder.loadingState === "loaded"
&& Activity.Data.SingleDocumentData.isInstance(dataHolder.data)
? dataHolder.data.document
: {};
const sceneReference = ViewSelectors.sceneReferenceByActivityId(ownProps.activity.id)(state);
if (sceneReference === undefined) {
throw new Error();
}
const documentModelTuple = ModelSelectors.documentModelTuple({ sceneReference })(state);
if (documentModelTuple === undefined || documentModelTuple.loadingState !== "loaded") {
return {};
}
const { documentModel, validatorProvider } = documentModelTuple.data;
const respondToComplaintFormModel = ModelSelectors.formModel({
sceneReference: sceneReference,
modelDescriptor: {name: "AnalyzeRootCause"}
})(state);
if (respondToComplaintFormModel === undefined || respondToComplaintFormModel.loadingState !== "loaded") {
return {};
}
const formModel = respondToComplaintFormModel.data as unknown as FormModel;
if (false === FormModel.isInstance(formModel)) {
return {};
}
const engineState = createEngineStore(
{
data: {
document
},
models: {
documentModel,
validatorProvider,
formModel
},
ui: {
readonly: true
},
locale: LocaleSelectors.locale()(state)
}
);
return defaultMapStateToProps(engineState, {});
},
FormEngineActions.mapDispatchToProps
)(function Engine(props: FormEngineRenderer.PropsType): JSX.Element | null {
return Object.keys(props).indexOf("state") > 0
? <ScrollHandler models={props.state.models} uiState={props.state.ui} {...props}>
<FormEngineContentBoxRenderer {...props}>
<FormEngineRenderer {...props} />
</FormEngineContentBoxRenderer>
</ScrollHandler>
: <div>LOADING</div>;
});
Your 2 containers look like this:
function FirstFormEngine(props: Props): JSX.Element {
return <FormEngineViews.FormEngine activity={props.activity} name={"FirstFormEngine"} />;
}
function SecondFormEngine(props: Props) {
return <div>
<FormEngineView2 name={"customFE2"}
activity={props.activity}/>
</div>;
}
Your container factory look like this:
export const ViewsMap: { [name: string]: React.ComponentType<View> } = {
FirstFormEngine: FirstFormEngine,
SecondFormEngine: ConnectedMultipleFormEngineOneActivity
};
Your application model looks like this:
{
name: "Multiple-fe-1-activity",
menu: {
name: "Multi FE in 1 Activity",
label: {
en: "Multi FE in 1 Activity",
de: "Multi FE in 1 Activity"
},
state: {
test: "multiple-form-engine",
instance: "Test"
}
},
flows: [
{
name: "welcome",
scenes: [
{
name: "about",
matchConditions: [
{
key: "test",
mustEqual: "multiple-form-engine"
},
{
key: "instance",
isSet: true
}
],
sceneChange: {
onEnter: [
{
type: "REGION_CLEAR"
},
{
type: "VIEW_ADD",
container: "FirstFormEngine",
models: [
{ name: "RespondToComplaint", modelType: "form"}
]
},
{
type: "VIEW_ADD",
container: "SecondFormEngine",
models: [
{ name: "AnalyzeRootCause", modelType: "form"}
]
}
]
}
}
]
}
]
}
with example above you can see:
- FirstFormEngine container loads RespondToComplaint Ui Model,
- SecondFormEngine container load AnalyzeRootCause from the code in the connected function. The declaration of the Form Model has to be included in application model in order to tell bap-client load it.
Example is tested with
- bap-client: 5.1.0
- bap-form-engine: 27.1.0
I hope it helps. In case you have further problem just comment in this article or call me via jabber ![]()
Cheers,
Tuan Do