Hey
We are working a rich text editor which will replace a text input in some forms when the proper annotation is added.
export function FormEngineEditorElement(
props: FormModelMap.FormModelComponentProps<FormModel.Control>
): React.ReactElement {
const activity = (props.config.renderOptions as any).activity;
const dataHolder = Activity.findDefaultDataHolder(activity);
const data = (dataHolder?.data as any)?.cddState?.cachedCdd?.cdd;
const locale = useSelector(localeSelector);
const elementPath = props.modelElement.elementPath;
const initialValue =
elementPath.reduce((prev, curr) => {
return prev?.[curr.elementName];
}, data ?? {}) ?? "";
const parentPath = props.config.parentPath;
const [label] = useState(
findObjectById(
props.config.renderOptions.state.models.documentModel.content.modelRoot.elements,
props.modelElement.elementRef
).label.find((l: any) => l.locale === locale.language).text
);
const contentDataState = data
? ContentState.createFromBlockArray(convertFromHTML(initialValue).contentBlocks)
: undefined;
const editorDataState = contentDataState ? EditorState.createWithContent(contentDataState) : undefined;
const [editorState, setEditorState] = useState<EditorState | undefined>(undefined);
const [activityId, setActivityId] = useState(activity.id);
const dispatch = useDispatch();
if (!editorState && editorDataState) {
setEditorState(editorDataState);
}
if (activityId !== activity.id) {
setActivityId(activity.id);
setEditorState(editorDataState);
}
const onEditorStateChange = (editorStateData: EditorState) => {
if (editorState) {
setEditorState(editorStateData);
}
};
const onBlur = () => {
const action = FormEngineActions.event({
activityId: activity.id,
engineEvent: {
type: "form-engine/event/VALUE_CHANGE",
payload: {
value: stateToHTML(editorState!.getCurrentContent()),
path: elementPath.map(p => ({ ...p, index: 1 })),
formModelElementPath: parentPath
}
}
});
dispatch(action);
};
return (
<>
<div style={{ marginBottom: "3px", fontWeight: "600" }}>
<label>{label}</label>
</div>
<DefaultEditor
editorState={editorState}
onChange={onEditorStateChange}
onBlur={onBlur}
toolbarPluginConfig={toolbarPluginConfig}
/>
</>
);
}
function CustomControl(props: FormModelMap.FormModelComponentProps<FormModel.Control>): React.ReactElement {
const rteAnnotation = props?.modelElement?.annotation?.find(
a => a.name === "useRichTextEditor" && a.value === "true"
);
if (rteAnnotation) {
return <FormEngineEditorElement {...props} />;
}
return <RelationshipFormModelMap.Control.component {...props} />;
}
const CustomFormModelMap: FormModelMap = {
...DefaultFormModelMap,
...RelationshipFormModelMap,
CustomScreenElement: { component: CustomScreenElement },
DetachedRepeat: { component: CustomDetachedRepeat },
Control: { component: CustomControl },
InlineRepeat: { component: CustomInlineRepeat },
ButtonPanel: { component: CustomButtonPanel }
};
We use props.config.parentPath to retrieve the initial value from the dataHolder. The problem appears when we want to have a detached repeat with the separate screen to edit the entries:
The elementPath does not include the array index of the entry. How is it handled for out-of-the-box controls? Maybe there is another way to work with the data holder

