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 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;
    }
}