vaadin / flow-components

Java counterpart of Vaadin Web Components
101 stars 66 forks source link

Mobile Browser don't handle this Button click properly (StateTree after applying changes missing) #1540

Open masbaehr opened 5 years ago

masbaehr commented 5 years ago

Hi, i am experiencing a strange issue with mobile browsers. On a Desktop Browser both buttons refresh the UI, but on a mobile browser they don't. However the Server Method is called in both cases. Analyzing the console output i noticed that the "StateTree after applying changes" statement is never printed on Mobile Chrome + Mobile Firefox, but on Desktop yes. So it seems some XHR message cannot be parsed or executed.

MWE:

import com.vaadin.flow.component.Html;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.spring.annotation.UIScope;

@Route("test123")
@UIScope
public class ButtonWeirdness extends Div {

    public ButtonWeirdness() {

        Button helloWorld = new Button("Hello World", new Icon(VaadinIcon.CHAT));
        helloWorld.addClickListener(l -> {
            Notification notification = new Notification("Hello World!", 3000, Notification.Position.MIDDLE);
            notification.open();
            System.out.println("helloWorld listener called");
        });
        add(helloWorld);
        //--------
        add(new Html("<br>"));
        Button helloWorldclone = new Button("Hello World Clone", new Icon(VaadinIcon.CHAT));
        //don't ask why i'm doing this ;-) I need to clone buttons in runtime and can't save the clicklistener to a variable for later adding
        helloWorldclone.addClickListener(l -> {
            helloWorld.click();
            System.out.println("helloWorldclone listener called");
        });
        add(helloWorldclone);

    }

}
Legioth commented 5 years ago

This seems to be some weird timing issue, potentially related to logic to suppress accidental duplicate clicks with a touch screen.

If I put a breakpoint in the beginning of the click listener of the button clone so that it helloWorld.click() isn't run immediately, then it works. It also works if I attach the phone to a remote debugger and use JavaScript to click the button clone.

I also tested adding a client-side click listener to the clone button that would directly do click() on the original button without bypassing the server. This only worked if I added a delay before actually doing click() and I tapped on some other part of the screen before that delay happened.

This can also be reproduced without any Vaadin functionality at all, so it seems like it's a browser "feature".

I can, however, suggest a workaround. You can directly trigger the click listener of the other button by using some semi-internal APIs: ComponentUtil.fireEvent(helloWorld, new ClickEvent<>(helloWorld));.

Legioth commented 5 years ago

I'll actually close this issue since it seems like we cannot really do anything about the way the browser ignores element.click() in some specific situations.

masbaehr commented 5 years ago

Cool thanks for the workaround it is enough to avoid the issue :)

Legioth commented 5 years ago

I traced down the issue to https://github.com/Polymer/polymer/issues/5289. The ticket suggests a workaround in the form of dispatching a non-bubbling event instead of doing element.click(). This is something we could do in Button.click(). I'll move the issue there.

web-padawan commented 4 years ago

See the related workaround in vaadin-upload component.

Also, starting from Polymer 3.3.0, there is a global setting for this:

import { setCancelSyntheticClickEvents } from '@polymer/polymer/lib/utils/settings.js';

setCancelSyntheticClickEvents(false);