Custom Form
Custom process forms can be useful if you need to render a form in a non-standard way. In the modeler, you can provide a form id, a list of form parameters and a list of outcomes for a custom form.
If you use an alternative UI technology (for example, React) then you need to get the form information and render the form using this information. You can obtain form information using the FormService
interface that has the following methods:
-
StartFormData getStartFormData​(String processDefinitionId)
-
TaskFormData getTaskFormData​(String taskId)
To render custom forms in the Start process or My tasks screens, you need to define the ProcessFormScreenCreator
for the custom
form type. To override the default ProcessFormScreenCreator
, you need to add the @Order
annotation.
Let’s look at the example of MyCustomProcessFormScreenCreator
that implements ProcessFormScreenCreator
:
@Component("samples_MyCustomProcessFormScreenCreator")
@Order(1) (1)
public class MyCustomProcessFormScreenCreator implements ProcessFormScreenCreator {
@Autowired
private ScreenBuilders screenBuilders;
@Override
public String isApplicableFor() { (2)
return "custom";
}
@Override
public Screen createStartProcessScreen(CreationContext creationContext) { (3)
Screen screen = screenBuilders.screen(creationContext.getFrameOwner())
.withScreenId(creationContext.getFormData().getScreenId())
.withOpenMode(OpenMode.DIALOG)
.build();
if (screen instanceof AcceptsProcessDefinition) { (4)
((AcceptsProcessDefinition) screen)
.setProcessDefinition(creationContext.getProcessDefinition());
}
return screen;
}
@Override
public Screen createUserTaskScreen(CreationContext creationContext) { (5)
Screen screen = screenBuilders.screen(creationContext.getFrameOwner())
.withScreenId(creationContext.getFormData().getScreenId())
.withOpenMode(OpenMode.DIALOG)
.build();
if (screen instanceof AcceptsTask) { (6)
((AcceptsTask) screen).setTask(creationContext.getTask());
}
return screen;
}
}
1 | The @Order annotation indicates that this implementation of ProcessForScreenCreator will be used first. |
2 | ScreenCreator will be applied to custom process forms. |
3 | Overrides the method for creating a start process form. |
4 | Checks if the screen implements AcceptsProcessDefinition . In this case, it is necessary to set ProcessDefiniton to the screen. |
5 | Overrides the method for creating a task process form. |
6 | Checks if the screen implements AcceptsTask . In this case, it is necessary to set Task to the screen. |
An example of the AcceptsProcessDefinition
interface:
public interface AcceptsProcessDefinition {
void setProcessDefinition(ProcessDefinition processDefinition);
}
An example of the AcceptsTask
interface:
public interface AcceptsTask {
void setTask(Task task);
}
XML descriptor of the custom start form that has only Start process button:
<window xmlns="http://jmix.io/schema/ui/window"
caption="msg://customStartForm.caption">
<layout>
<button id="startProcessBtn" caption="msg://startProcessBtn.caption"/>
</layout>
</window>
Screen controller of the custom start form:
@UiController("smpl_CustomStartForm")
@UiDescriptor("custom-start-form.xml")
public class CustomStartForm extends Screen implements AcceptsProcessDefinition {
private ProcessDefinition processDefinition;
@Autowired
private RuntimeService runtimeService;
@Subscribe("startProcessBtn")
public void onStartProcessBtnClick(Button.ClickEvent event) {
runtimeService.startProcessInstanceById(processDefinition.getId());
closeWithDefaultAction();
}
@Override
public void setProcessDefinition(ProcessDefinition processDefinition) {
this.processDefinition = processDefinition;
}
}
XML descriptor of the custom task form that has only Task complete button:
<window xmlns="http://jmix.io/schema/ui/window"
caption="msg://customTaskForm.caption">
<layout>
<button id="completeTaskBtn" caption="msg://completeTaskBtn.caption"/>
</layout>
</window>
Screen controller of the custom task form:
@UiController("smpl_CustomTaskForm")
@UiDescriptor("custom-task-form.xml")
public class CustomTaskForm extends Screen implements AcceptsTask {
private Task task;
@Autowired
private TaskService taskService;
@Subscribe("completeTaskBtn")
public void onCompleteTaskBtnClick(Button.ClickEvent event) {
taskService.complete(task.getId());
closeWithDefaultAction();
}
@Override
public void setTask(Task task) {
this.task = task;
}
}