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() { (3)
        return "custom";
    } (2)

    @Override
    public Screen createStartProcessScreen(CreationContext creationContext) { (3)
        Screen screen = screenBuilders.screen(creationContext.getFrameOwner())
                .withScreenId(creationContext.getFormData().getScreenId())
                .withOpenMode(OpenMode.DIALOG)
                .build();
        if (screen instanceof AcceptsProcessDefinitionData) { (4)
            ((AcceptsProcessDefinitionData) screen)
                    .setProcessDefinitionData(creationContext.getProcessDefinitionData());
        }
        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 AcceptsTaskData) { (6)
            ((AcceptsTaskData) screen).setTaskData(creationContext.getTaskData());
        }
        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 AcceptsProcessDefinitionData. In this case, it is necessary to set ProcessDefinitonData to the screen.
5 Overrides the method for creating a task process form.
6 Checks if the screen implements AcceptsTaskData. In this case, it is necessary to set TaskData to the screen.

An example of the AcceptsProcessDefinitionData interface:

public interface AcceptsProcessDefinitionData {
    void setProcessDefinitionData(ProcessDefinitionData processDefinitionData);
}

An example of the AcceptsTaskData interface:

public interface AcceptsTaskData {
    void setTaskData(TaskData taskData);
}

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 AcceptsProcessDefinitionData {

    private ProcessDefinitionData processDefinitionData;

    @Autowired
    private RuntimeService runtimeService;

    @Subscribe("startProcessBtn")
    public void onStartProcessBtnClick(Button.ClickEvent event) {
        runtimeService.startProcessInstanceById(processDefinitionData.getId());
        closeWithDefaultAction();
    }

    @Override
    public void setProcessDefinitionData(ProcessDefinitionData processDefinitionData) {
        this.processDefinitionData = processDefinitionData;
    }
}

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 AcceptsTaskData {

    private TaskData taskData;

    @Autowired
    private TaskService taskService;

    @Subscribe("completeTaskBtn")
    public void onCompleteTaskBtnClick(Button.ClickEvent event) {
        taskService.complete(taskData.getId());
        closeWithDefaultAction();
    }

    @Override
    public void setTaskData(TaskData taskData) {
        this.taskData = taskData;
    }
}