Custom Form

When an element needs a form that cannot be shown as a simple Input Dialog and cannot use the usual Jmix View annotation-driven approach, you can supply a custom form. This form may still be a Jmix view, or it can be built with an alternative UI technology (e.g., React).

In the modeler, you will need to provide an id for this form. The custom form must read the supplied input parameters and return the outcomes.

custom form

Implementing a Custom Jmix Form

To render custom forms in the Start process or My tasks views, implement the ProcessFormViewCreator interface and register it for the custom form type.

Let’s look at the example of MyCustomProcessFormViewCreator that implements ProcessFormViewCreator:

@Component("MyCustomProcessFormViewCreator")
@Order(1) (1)
public class MyCustomProcessFormViewCreator implements ProcessFormViewCreator {

    @Autowired
    private DialogWindows dialogWindows;

    @Override
    public String isApplicableFor() {
        return "custom";
    }

    @Override
    public DialogWindow<?> createStartProcessView(CreationContext creationContext) { (2)
        FormData formData = creationContext.getFormData();
        View origin = creationContext.getOrigin();
        String viewId = formData.getScreenId();

        DialogWindow dialog = dialogWindows
                .view(origin, viewId)
                .open();

        if (dialog.getView() instanceof AcceptsProcessDefinition) { (3)
            ((AcceptsProcessDefinition) dialog.getView())
                    .setProcessDefinition(creationContext.getProcessDefinition());
        }
        return dialog;
    }

    @Override
    public DialogWindow<?> createUserTaskView(CreationContext creationContext) { (4)
        FormData formData = creationContext.getFormData();
        View origin = creationContext.getOrigin();

        String viewId = formData.getScreenId();
        DialogWindow dialog = dialogWindows
                .view(origin, viewId)
                .build();

        if (dialog.getView() instanceof AcceptsTask) { (5)
            ((AcceptsTask) dialog.getView())
                    .setTask(creationContext.getTask());
        }
        return dialog;
    }
}
1 The @Order annotation makes this implementation the first one the framework will consider.
2 Overrides the method for creating a start process form.
3 Checks if the view implements AcceptsProcessDefinition. In this case, it is necessary to set ProcessDefiniton to the view.
4 Overrides the method for creating a task process form.
5 Checks if the view implements AcceptsTask. In this case, it is necessary to set Task to the view.

Custom Start Form

Begin with adding the supporting AcceptsProcessDefinition interface:

public interface AcceptsProcessDefinition {
    void setProcessDefinition(ProcessDefinition processDefinition);
}

XML descriptor of the custom start form that has only Start process button:

<view xmlns="http://jmix.io/schema/flowui/view"
      title="msg://customStartForm.title">
    <layout>
        <button id="startProcessBtn" text="msg://startProcessBtn.caption"/>
    </layout>
</view>

View controller of the custom start form:

@ViewController(id = "CustomStartForm")
@ViewDescriptor(path = "custom-start-form.xml")
public class CustomStartForm extends StandardView implements AcceptsProcessDefinition {

    private ProcessDefinition processDefinition;

    @Autowired
    private RuntimeService runtimeService;

    @Override
    public void setProcessDefinition(ProcessDefinition processDefinition) {
        this.processDefinition = processDefinition;
    }

    @Subscribe(id = "startProcessBtn", subject = "clickListener")
    public void onStartProcessBtnClick(final ClickEvent<JmixButton> event) {
        runtimeService.startProcessInstanceByKey(processDefinition.getKey());
        closeWithDefaultAction();
    }
}

Custom User Task Form

First, add the supporting AcceptsTask interface:

public interface AcceptsTask {
    void setTask(Task task);
}

XML descriptor of the custom task form that has only Task complete button:

<view xmlns="http://jmix.io/schema/flowui/view"
      title="msg://com.company.bpmex1.view.forms/customTaskForm.title">
    <layout>
        <button id="completeTaskBtn" text="msg://com.company.bpmex1.view.forms/completeTaskBtn.text"/>
    </layout>
</view>

View controller of the custom task form:

@ViewController("CustomTaskForm")
@ViewDescriptor("custom-task-form.xml")
public class CustomTaskForm extends StandardView implements AcceptsTask {

    private Task task;

    @Autowired
    private TaskService taskService;

    @Subscribe("completeTaskBtn")
    public void onCompleteTaskBtnClick(ClickEvent<JmixButton> event) {
        taskService.complete(task.getId());
        closeWithDefaultAction();
    }

    @Override
    public void setTask(Task task) {
        this.task = task;
    }
}

Using Alternative UI Technology

When using an alternative UI technology (e.g., React), call Flowable’s FormService to get the necessary data to render forms. It has the following methods:

  • StartFormData getStartFormData (String processDefinitionId)

  • TaskFormData getTaskFormData (String taskId)