3.5.6. Dialogs

The Dialogs interface is designed to display standard dialogs windows. Its createMessageDialog(), createOptionDialog() and createInputDialog() methods are the entry points to the fluent API that allows you to construct and show dialogs.

Appearance of the dialogs can be customized using SCSS variables with $cuba-window-modal-* prefix. You can change these variables in the visual editor after creating a theme extension or a custom theme.

Message Dialog

In the following example, a message dialog is shown when the user clicks a button:

@Inject
private Dialogs dialogs;

@Subscribe("showDialogBtn")
protected void onShowDialogBtnClick(Button.ClickEvent event) {
    dialogs.createMessageDialog().withCaption("Information").withMessage("Message").show();
}

Use the withMessage() method to pass the message text.

You can use \n characters for line breaks in messages. In order to show HTML, use the withContentMode() method with ContentMode.HTML parameter. When using HTML, don’t forget to escape data to prevent code injection.

You can pass true to the withHtmlSanitizer() method to enable HTML sanitization for the dialog content. In this case, ContentMode.HTML parameter must be passed to the withContentMode() method.

protected static final String UNSAFE_HTML = "<i>Jackdaws </i><u>love</u> <font size=\"javascript:alert(1)\" " +
            "color=\"moccasin\">my</font> " +
            "<font size=\"7\">big</font> <sup>sphinx</sup> " +
            "<font face=\"Verdana\">of</font> <span style=\"background-color: " +
            "red;\">quartz</span><svg/onload=alert(\"XSS\")>";

@Inject
private Dialogs dialogs;

@Subscribe("showMessageDialogOnBtn")
public void onShowMessageDialogOnBtnClick(Button.ClickEvent event) {
    dialogs.createMessageDialog()
            .withCaption("MessageDialog with Sanitizer")
            .withMessage(UNSAFE_HTML)
            .withContentMode(ContentMode.HTML)
            .withHtmlSanitizer(true)
            .show();
}

@Subscribe("showMessageDialogOffBtn")
public void onShowMessageDialogOffBtnClick(Button.ClickEvent event) {
    dialogs.createMessageDialog()
            .withCaption("MessageDialog without Sanitizer")
            .withMessage(UNSAFE_HTML)
            .withContentMode(ContentMode.HTML)
            .withHtmlSanitizer(false)
            .show();
}

The value passed to the withHtmlSanitizer() method overrides the value of global cuba.web.htmlSanitizerEnabled configuration property.

The following methods allow you to customize the look and behavior of the message dialog:

  • withModal() – if false is passed, the dialog is shown as non-modal, which allows a user to interact with the other parts of the application.

  • withCloseOnClickOutside() – when true is passed and the dialog is modal, allows a user to close the dialog by clicking on the application window outside of the dialog.

  • withMaximized() – when true is passed, the dialog should be maximized.

  • withWidth(), withHeight() allow you to specify the desired dialog geometry.

For example:

@Inject
private Dialogs dialogs;

@Subscribe("showDialogBtn")
protected void onShowDialogBtnClick(Button.ClickEvent event) {
    dialogs.createMessageDialog()
            .withCaption("Information")
            .withMessage("<i>Message<i/>")
            .withContentMode(ContentMode.HTML)
            .withCloseOnClickOutside(true)
            .withWidth("100px")
            .withHeight("300px")
            .show();
}
Option Dialog

The option dialog displays a message and a set of buttons for user reaction. Use withActions() method to provide actions, each of which is represented by a button in the dialog. For example:

@Inject
private Dialogs dialogs;

@Subscribe("showDialogBtn")
protected void onShowDialogBtnClick(Button.ClickEvent event) {
    dialogs.createOptionDialog()
            .withCaption("Confirm")
            .withMessage("Are you sure?")
            .withActions(
                new DialogAction(DialogAction.Type.YES, Action.Status.PRIMARY).withHandler(e -> {
                    doSomething();
                }),
                new DialogAction(DialogAction.Type.NO)
            )
            .show();
}

When a button is clicked, the dialog closes and invokes actionPerform() method of the corresponding action.

The DialogAction base class is designed to create actions with standard names and icons. Five types of actions defined by the DialogAction.Type enum are supported: OK, CANCEL, YES, NO, CLOSE. Names of corresponding buttons are extracted from the main message pack.

The second parameter of the DialogAction constructor is used to assign a special visual style for a button representing the action. Status.PRIMARY highlights the corresponding button and makes it selected, which is provided by the c-primary-action style. If multiple actions with Status.PRIMARY are defined for the dialog, only the first action’s button will get the style and focus.

Input Dialog

Input dialog is a versatile tool which allows you to construct input forms using API and can often save you from creating screens for trivial data input. It enables entering values of different types, validates the input and provides different actions to be selected by the user.

Let’s consider some examples.

  1. Input dialog with parameters of standard types and standard OK/Cancel actions:

    @Inject
    private Dialogs dialogs;
    
    @Subscribe("showDialogBtn")
    private void onShowDialogBtnClick(Button.ClickEvent event) {
        dialogs.createInputDialog(this)
                .withCaption("Enter some values")
                .withParameters(
                        InputParameter.stringParameter("name")
                            .withCaption("Name").withRequired(true), (1)
                        InputParameter.doubleParameter("quantity")
                            .withCaption("Quantity").withDefaultValue(1.0), (2)
                        InputParameter.entityParameter("customer", Customer.class)
                            .withCaption("Customer"), (3)
                        InputParameter.enumParameter("status", Status.class)
                            .withCaption("Status") (4)
                )
                .withActions(DialogActions.OK_CANCEL) (5)
                .withCloseListener(closeEvent -> {
                    if (closeEvent.closedWith(DialogOutcome.OK)) { (6)
                        String name = closeEvent.getValue("name"); (7)
                        Double quantity = closeEvent.getValue("quantity");
                        Optional<Customer> customer = closeEvent.getOptional("customer"); (8)
                        Status status = closeEvent.getValue("status");
                        // process entered values...
                    }
                })
                .show();
    }
    1 - specifies a mandatory string parameter.
    2 - specifies a double parameter with default value.
    3 - specifies an entity parameter.
    4 - specifies an enumeration parameter.
    5 - specifies a set of actions represented by buttons at the bottom of the dialog.
    6 - in the close listener, we can check what action was used by the user.
    7 - the close event contains entered values that can be obtained using parameter identifiers.
    8 - you can get a value wrapped in Optional.
  2. Input dialog with a custom parameter:

    @Inject
    private Dialogs dialogs;
    @Inject
    private UiComponents uiComponents;
    
    @Subscribe("showDialogBtn")
    private void onShowDialogBtnClick(Button.ClickEvent event) {
        dialogs.createInputDialog(this)
                .withCaption("Enter some values")
                .withParameters(
                        InputParameter.stringParameter("name").withCaption("Name"),
                        InputParameter.parameter("customer") (1)
                                .withField(() -> {
                                    LookupField<Customer> field = uiComponents.create(
                                            LookupField.of(Customer.class));
                                    field.setOptionsList(dataManager.load(Customer.class).list());
                                    field.setCaption("Customer"); (2)
                                    field.setWidthFull();
                                    return field;
                                })
                )
                .withActions(DialogActions.OK_CANCEL)
                .withCloseListener(closeEvent -> {
                    if (closeEvent.closedWith(DialogOutcome.OK)) {
                        String name = closeEvent.getValue("name");
                        Customer customer = closeEvent.getValue("customer"); (3)
                        // process entered values...
                    }
                })
                .show();
    }
    1 - specifies a custom parameter.
    2 - a caption for the custom parameter is specified in the created component.
    3 - value of the custom parameter is obtained in the same way as for standard parameters.
  3. Input dialog with custom actions:

    @Inject
    private Dialogs dialogs;
    
    @Subscribe("showDialogBtn")
    private void onShowDialogBtnClick(Button.ClickEvent event) {
        dialogs.createInputDialog(this)
                .withCaption("Enter some values")
                .withParameters(
                    InputParameter.stringParameter("name").withCaption("Name")
                )
                .withActions( (1)
                        InputDialogAction.action("confirm")
                                .withCaption("Confirm")
                                .withPrimary(true)
                                .withHandler(actionEvent -> {
                                    InputDialog dialog = actionEvent.getInputDialog();
                                    String name = dialog.getValue("name"); (2)
                                    dialog.closeWithDefaultAction(); (3)
                                    // process entered values...
                                }),
                        InputDialogAction.action("refuse")
                                .withCaption("Refuse")
                                .withValidationRequired(false)
                                .withHandler(actionEvent ->
                                    actionEvent.getInputDialog().closeWithDefaultAction())
                )
                .show();
    }
    1 - withActions() method can accept an array of custom actions.
    2 - in the action handler, you can get a parameter value from the dialog.
    3 - custom action does not close the dialog itself, so you should do it at some moment.
  4. Input dialog with custom validator:

    @Inject
    private Dialogs dialogs;
    
    @Subscribe("showDialogBtn")
    private void onShowDialogBtnClick(Button.ClickEvent event) {
        dialogs.createInputDialog(this)
                .withCaption("Enter some values")
                .withParameters(
                        InputParameter.stringParameter("name").withCaption("Name"),
                        InputParameter.entityParameter("customer", Customer.class).withCaption("Customer")
                )
                .withValidator(context -> { (1)
                    String name = context.getValue("name"); (2)
                    Customer customer = context.getValue("customer");
                    if (Strings.isNullOrEmpty(name) && customer == null) {
                        return ValidationErrors.of("Enter name or select a customer");
                    }
                    return ValidationErrors.none();
                })
                .withActions(DialogActions.OK_CANCEL)
                .withCloseListener(closeEvent -> {
                    if (closeEvent.closedWith(DialogOutcome.OK)) {
                        String name = closeEvent.getValue("name");
                        Customer customer = closeEvent.getValue("customer");
                        // process entered values...
                    }
                })
                .show();
    }
    1 - the custom validator is needed to ensure at least one parameter is entered.
    2 - in the validator, parameter values can be obtained from the context object.
  5. Input dialog with a FileDescriptor parameter:

    @Inject
    private Dialogs dialogs;
    
    @Subscribe("showDialogBtn")
    public void onShowDialogBtnClick(Button.ClickEvent event) {
        dialogs.createInputDialog(this)
                .withCaption("Select the file")
                .withParameters(
                        InputParameter.fileParameter("fileField") (1)
                                .withCaption("File"))
                .withCloseListener(closeEvent -> {
                    if (closeEvent.closedWith(DialogOutcome.OK)) {
                        FileDescriptor fileDescriptor = closeEvent.getValue("fileField");  (2)
                    }
                })
                .show();
    }
    1 - specifies a FileDescriptor parameter.
    2 - the close event contains entered value that can be obtained using a parameter identifier.