Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dialog height change causes button click to not register #5267

Open
sujoykd opened this issue Jul 18, 2023 · 8 comments
Open

Dialog height change causes button click to not register #5267

sujoykd opened this issue Jul 18, 2023 · 8 comments
Labels
needs discussion No decision yet, discussion needed needs research

Comments

@sujoykd
Copy link
Contributor

sujoykd commented Jul 18, 2023

Description of the bug

The scenario is that I have a dialog with a number of input fields. These fields have associated binder validations. When there is an error in the data entered into the field, the error message shows up causing the dialog to grow in height.

If I click on the button directly after correcting the field value, then it validates the input again immediately. This in turn removes the error message, which causes the dialog height to change. If the dialog height changes significantly enough, the mouse may no longer be on top of the Save button when the click is registered. This means that the click registers on the dialog background, and no events are sent to the server.

Expected behavior

When the user clicks on a button it should cause the button to be clicked, and the events should be sent to the server.

Minimal reproducible example

  • Type in 'abc#@gmail.com' in the email field and click on "Add" button. Notice that the "saved!" notification shows up.

  • Click in the email input field and remove the '#' character. Click directly on the "Add" button. Notice that the dialog changes height but the notification does not show up.

@PageTitle("Dialog")
@Route(value = "dialog", layout = MainLayout.class)
@RouteAlias(value = "", layout = MainLayout.class)
public class DialogTest extends VerticalLayout {
    private Binder<User> binder;
    private final TextField firstNameField;
    private final TextField lastNameField;
    private final TextField commentField;
    private final TextField emailField;

    public DialogTest() {
        this.firstNameField = new TextField("First Name");
        this.lastNameField = new TextField("Last Name");
        this.commentField = new TextField("Comment");
        this.emailField = new TextField("Email");

        this.initDialog();
        this.initBinder();
    }

    private void initBinder() {
        this.binder = new BeanValidationBinder<>(User.class);

        // firstNameō
        this.binder.forField(this.firstNameField)
                   .withValidator(firstName -> firstName.length() > 1,
                                  "The first name must contains at least 2 characters")
                   .asRequired()
                   .bind(User::getFirstName, User::setFirstName);

        // lastName
        this.binder.forField(this.lastNameField)
                   .asRequired("Last name can't be empty")
                   .bind(User::getLastName, User::setLastName);

        // comment
        this.binder.forField(this.commentField).bind(User::getComment, User::setComment);

        // email
        this.binder.forField(this.emailField)
                   .withValidator(
                                  new EmailValidator("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed faucibus leo et elementum placerat. Suspendisse potenti. Etiam vehicula sapien vitae ultrices consectetur. Maecenas bibendum ornare enim cursus rhoncus. Suspendisse at tortor purus. Quisque finibus, lacus quis volutpat ornare, enim massa lobortis augue, a pharetra purus sapien quis metus. Sed dapibus aliquet ipsum, at placerat nisl elementum nec. Quisque velit magna, pulvinar eget consectetur quis, ultricies eu eros. Nulla eros orci, accumsan congue consectetur a, ultrices sit amet metus. Nullam a augue scelerisque, ullamcorper risus a, auctor ipsum. Curabitur quis nulla commodo, lacinia sem at, gravida nisi."))
                   .bind(User::getEmail, User::setEmail);
    }

    private void initDialog() {
        final Dialog dialog = new Dialog();

        dialog.setHeaderTitle("New employee");

        final VerticalLayout dialogLayout = this.createDialogLayout();
        dialog.add(dialogLayout);

        final Button saveButton = this.createSaveButton(dialog);
        final Button cancelButton = new Button("Cancel", e -> dialog.close());
        dialog.getFooter().add(cancelButton);
        dialog.getFooter().add(saveButton);

        final Button button = new Button("Show dialog", e -> dialog.open());

        this.add(dialog, button);
    }

    private VerticalLayout createDialogLayout() {
        final VerticalLayout dialogLayout = new VerticalLayout(this.firstNameField,
                                                               this.lastNameField,
                                                               this.commentField,
                                                               this.emailField);
        dialogLayout.setPadding(false);
        dialogLayout.setSpacing(false);
        dialogLayout.setAlignItems(FlexComponent.Alignment.STRETCH);
        dialogLayout.getStyle().set("width", "18rem").set("max-width", "100%");

        return dialogLayout;
    }

    private Button createSaveButton(final Dialog dialog) {
        final Button saveButton = new Button("Add", e -> Notification.show("saved!", 1000, Position.BOTTOM_CENTER));
        saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);

        return saveButton;
    }

}

Versions

  • Vaadin / Flow version: 23.3.17
  • Java version: 11
@sissbruecker sissbruecker transferred this issue from vaadin/flow Jul 19, 2023
@sissbruecker
Copy link
Contributor

sissbruecker commented Jul 19, 2023

This is a common UX issue with vertical forms that validate on blur:

Some common solutions seem to be:

  • Reserve some space for the error message so that showing / hiding the error does not affect the layout
  • Minimize height of the error message, while increasing size of the submit button
  • Do not validate on blur, but on submit button click
  • Disable the button while the form is invalid

@jouni
Copy link
Member

jouni commented Jul 19, 2023

A very classic problem, which I remember we addressed somehow already in IT Mill Toolkit (aka Vaadin) 4 or 5. Not sure, but it might still be there in Vaadin 8. @mstahv, @emarc, and @Artur- might remember that as well.

@sissbruecker
Copy link
Contributor

Artur mentioned it yesterday: vaadin/framework@da211e9

It apparently involves listening for mousedown on the button, and then programmatically triggering click on mouseout. And then fixing several regressions afterwards. Not sure if we want to go there.

@rolfsmeds
Copy link
Contributor

It seems that the best universal solution would be to disable validation on blur (or any other field-specific event), and only validate when explicitly triggered through the binder (binder.validate()).

The least problematic solution for now is probably to construct the UI in a way that prevents shifting the button's position, e.g. by wrapping the form in a Scroller with a fixed default height, and placing the button below it. That way, when the height of the form changes, the presence of a scrollbar may be affected but the button stays put.

@rolfsmeds rolfsmeds added needs discussion No decision yet, discussion needed needs research labels Jul 19, 2023
@sujoykd
Copy link
Contributor Author

sujoykd commented Jul 19, 2023

For the current project., disabling validation on blur is not desired since there are complex forms with multiple inter dependent fields, and the user relies on getting feedback immediately.

Keeping enough space reserved for the error message is one option that is being evaluated.

@Avec112
Copy link

Avec112 commented Apr 15, 2024

I am experiencing exactly this issue as mentioned in the new forum here. I have a narrow form. Leaving the focused textfield to press cancel button triggers validation, which renders error message , which in turn moves the cancel button bellow the mouse cursor. If I press and release cancel button very fast there is no problem. Pressing and waiting for the button to be moved down and then release results in this issue.

@Avec112
Copy link

Avec112 commented Apr 15, 2024

I believe this fixed the problem since 24.3.0-beta1. I have this issue with 24.2.5 but the lost focus validation is gone with 23.3.9.

@rolfsmeds
Copy link
Contributor

Now that the Dialog (since 23.1) has a built-in static footer, I would recommend placing buttons there, and defining a fixed height for the Dialog. That way, when validation errors appear/disappear, and the form's height changes, the buttons will stay put.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs discussion No decision yet, discussion needed needs research
Projects
None yet
Development

No branches or pull requests

5 participants