event loop gwt scheduleDeferred

A browser event loop is a thread started by the browser that is constantly scanning for and running different events, just like it sounds. As events occur they are put in the event queue and run in turn by the one event thread. Your javascript should not create its own loops waiting for it to complete or anything like that…it will block that one continuous event loop thread. Instead you would use something like setTimeout or setInterval and check for whatever conditions you are waiting for so the browser can do work while it ‘waits’.

GWT is nice in that it can co-opt this process somewhat using the scheduler — in your case where you want to run something after the event loop ‘completes’ you will probably want to use scheduleFinally or scheduleDeferred. It will inject a handler for a piece of code into the event queue so that it will run after all other code in the current execution context (current execution context == where ever you are in the current JavaScript object hierarchy with the window as the root object) is run but before the next event that is placed in the queue.

.


Example of setting focus

The TextBox needs to be attached to the page before you can focus it.
So, the following should fail:
TextBox textBox = new TextBox();
textBox.setFocus(true); // Fail: not attached to the DOM
RootPanel.get().add(textBox);
And the following should work:
TextBox textBox = new TextBox();
RootPanel.get().add(textBox);
textBox.setFocus(true); // Works: attached to the DOM

The reason a deferred command works is because the deferred command fires after the current event loop, which means that your text box gets attached.

TextBox textBox = new TextBox();
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
textBox.setFocus(true);
}
});
RootPanel.get().add(textBox); // Fires before setFocus
 

Notice that I said it should work.  In reality, focus can behave very weirdly, especially in IE.  I’ve found that if you create an element and try to focus it in the same event loop, the focus often fails in IE.  If your TextBox was already created (say in a constructor), it should be focusable as soon as you attach it to the DOM.  In either case, using a deferred command should always work.

We should be able to just make all calls to focus use a deferred command in IE, but then again maybe not.  What if you call focus() then blur() synchronously?  That means blur also needs to be in a deferred command.  I think it still works, but we’ll have to test all the use cases to make sure.

.


Example of enforcing text max length

Need a scheduler because we should truncate after value is set to the widget, without the scheduleDeferred, we are truncating the text that has not appended the current user type char.

This textarea is defined inside a DynoTextArea class.

    private TextArea textArea = new TextArea()
    {
        @Override
        public void onBrowserEvent(Event event)
        {
            // Checking for paste event
            if (event.getTypeInt() == Event.ONPASTE)
            {
                if (DynoTextArea.this.truncateWhenExceedMax)
                {
                    //need a scheduler here because we should truncate after value is set to the widget
                    Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand()
                    {

                        @Override
                        public void execute()
                        {
                            String deferedText = DynoTextArea.this.textArea.getValue();
                            if (deferedText != null && deferedText.length() > getMaxLength())
                            {
                                DynoTextArea.this.textArea.setValue(deferedText.substring(0, getMaxLength()));
                            }
                        }
                    });
                }
                return;
            }

            // Checking for keyUp event.
            if (event.getTypeInt() == Event.ONKEYDOWN)
            {
                String text = DynoTextArea.this.textArea.getValue() == null ? "" : DynoTextArea.this.textArea.getValue();
                //when truncate is set, only allow several keys when max is reached
                if (DynoTextArea.this.truncateWhenExceedMax && text.length() >= getMaxLength() && isDisplayCharacterEvent(event))
                {
                    event.preventDefault();
                    return;
                }
            }
            super.onBrowserEvent(event);
        }

    };

    /**
     * determint whether the passed in event is a display char key down event.
     * @param event
     * @return
     */
    public static boolean isDisplayCharacterEvent(Event event)
    {
        return event.getKeyCode() != KeyCodes.KEY_LEFT && event.getKeyCode() != KeyCodes.KEY_TAB && event.getKeyCode() != KeyCodes.KEY_RIGHT &&
            event.getKeyCode() != KeyCodes.KEY_DELETE && event.getKeyCode() != KeyCodes.KEY_BACKSPACE && event.getKeyCode() != KeyCodes.KEY_SHIFT &&
            event.getKeyCode() != KeyCodes.KEY_CTRL && event.getKeyCode() != KeyCodes.KEY_HOME && event.getKeyCode() != KeyCodes.KEY_END;
    }
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s