0

Context: In a Vaadin 23.2.8 form there is a TextField and a Button.

What I want to do / expected behavior: In the ValueChangeListener of the TextField there should open a dialog. The dialog should be visible until the user closes it. The button should execute in the background (or after the user closes the dialog, which would also be fine).

Unexpected behavior: When a user types something into the TextField and clicks at the button, then the dialog pops up and vanishes after a fraction of a second. And the button is not executed.

What does work: When the user types something into the TextField, then leaves the TextField (by clicking somewhere outside the TextField) and then clicks the button, everything works as expected.

Code / Small reproducible example:

@Route("sandbox")
public class SandboxView extends VerticalLayout {
public SandboxView() {
    TextField textfield = new TextField("1. Type something");
    textfield.addValueChangeListener(event -> {
        new Dialog(new Text("Some text in dialog")).open();
    });
    this.add(textfield);

    Button button = new Button("2. Click me");
    button.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
    button.setDisableOnClick(true);
    button.addClickListener(event -> {
        System.out.println("Button was clicked");
        button.setEnabled(true);
    });
    this.add(button);
  }
}

Questions:

  1. Is it forbidden to open a Dialog in a ValueChangeListener in Vaadin?
  2. What can I do to get the expected behavior?
S. Doe
  • 685
  • 1
  • 6
  • 25
  • 1
    Your expected behavior is still describing the technical implementation of how you're trying to do something. What's the UI behavior you want to achieve? – ollitietavainen Nov 28 '22 at 07:49
  • @ollitietavainen The use case is this: when the user changes the value of the TextField (and some other conditions are met) then the system should immediately (=not wait until save action) give a hint that he/she should also change this value in another system (because both systems should be in sync - and there is no automatic interface yet and maybe never will be). The button is just to save the record. – S. Doe Nov 30 '22 at 10:23

2 Answers2

1

This happens because dialogs are by default configured to close when the user clicks outside the dialog. You can change this using the setCloseOnOutsideClick method.

Leif Åstrand
  • 7,820
  • 13
  • 19
  • You are right: `dialog.setCloseOnOutsideClick(false);` prevents the dialog to disappear. Unfortunately this would be the only dialog that is not closed on outside click. Can I reactivate that after a second or so (just long enough that the dialog doesn't disappear immediately)? I started a Thread with a Runnable that calls `Thread.sleep(1000); ui.access(() -> {dialog.setCloseOnOutsideClick(true);});` and it runs successfully (tested with some System.out.println(xxx) calls) but the Dialog doesn't close on outside click. – S. Doe Dec 04 '22 at 09:16
  • 1
    You need to have `@Push` or UI polling active for an async `access` to have an immediate impact. In this case, polling might be more appropriate since it's only needed for that case. If doing it so, then you could also restore the feature in the poll listener instead of dispatching a separate thread. – Leif Åstrand Dec 04 '22 at 17:50
0

The approach that works for me now is to show a Notification instead of a Dialog.

When opening a Dialog (even with dialog.setCloseOnOutsideClick(false) - a good hint of Leif), some other side effects occurred sometimes:

  • E.g. the Button ClickListener didn't execute or even froze (because of setDisableOnClick(true) the Button was disabled but the ClickListener wasn't called and therefore it couldn't reenable the Button by calling setEnabled(true)).
  • Also some other UI events didn't happen reliable when opening a Dialog, e.g. opening a Details element.

Unfortunately I couldn't reproduce these effects in a small code example.

With a Notification none of these side effects occurred.

S. Doe
  • 685
  • 1
  • 6
  • 25