Easy firing click event from code in GWT

Firing native events in GWT can be a real pain. If you need to fire a click event when the user press ENTER (or any other key that you want to work like CLICK) on any custom-made element, theoretically you should use:

*DomEvent.fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers) * Minimal code (without required parameters) linked with this approach: NativeEvent event = Document.get().createChangeEvent();
DomEvent.fireNativeEvent(event, this);
public final NativeEvent createClickEvent(int detail, int screenX, int screenY, int clientX, int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey, boolean metaKey) This is the place where native JSNI approach is much more clearer: public static native void click(Element element)/*-{
element.click();
}-*/;

This approach is very useful for custom made buttons that for some reason can not extend basic Button class. In any other case try not to simulate “user actions” in your handlers. Launch designated business methods instead.

You May Also Like

Journal.IO 1.3 released

AboutJust a moment ago (in February 17th) Journal.IO 1.3 has been released. Journal.IO (https://github.com/sbtourist/Journal.IO) is a lightweight, zero-dependency journal storage implementation written in Java. We use it in our project for storing appl...AboutJust a moment ago (in February 17th) Journal.IO 1.3 has been released. Journal.IO (https://github.com/sbtourist/Journal.IO) is a lightweight, zero-dependency journal storage implementation written in Java. We use it in our project for storing appl...

Simple trick to DRY your Grails controller

Grails controllers are not very DRY. It's easy to find duplicated code fragments in default generated controller. Take a look at code sample below. It is duplicated four times in show, edit, update and delete actions:

class BookController {
def show() {
def bookInstance = Book.get(params.id)
if (!bookInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), params.id])
redirect(action: "list")
return
}
[bookInstance: bookInstance]
}
}

Why is it duplicated?

There is a reason for that duplication, though. If you move this snippet to a method, it can redirect to "list" action, but it can't prevent controller from further execution. After you call redirect, response status changes to 302, but after method exits, controller still runs subsequent code.

Solution

At TouK we've implemented a simple trick to resolve that situation:

  1. wrap everything with a simple withStoppingOnRender method,
  2. whenever you want to render or redirect AND stop controller execution - throw EndRenderingException.

We call it Big Return - return from a method and return from a controller at once. Here is how it works:

class BookController {
def show(Long id) {
withStoppingOnRender {
Book bookInstance = Book.get(id)
validateInstanceExists(bookInstance)
[bookInstance: bookInstance]
}
}

protected Object withStoppingOnRender(Closure closure) {
try {
return closure.call()
} catch (EndRenderingException e) {}
}

private void validateInstanceExists(Book instance) {
if (!instance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), params.id])
redirect(action: "list")
throw new EndRenderingException()
}
}
}

class EndRenderingException extends RuntimeException {}

Example usage

For simple CRUD controllers, you can use this solution and create some BaseController class for your controllers. We use withStoppingOnRender in every controller so code doesn't look like a spaghetti, we follow DRY principle and code is self-documented. Win-win-win! Here is a more complex example:

class DealerController {
@Transactional
def update() {
withStoppingOnRender {
Dealer dealerInstance = Dealer.get(params.id)
validateInstanceExists(dealerInstance)
validateAccountInExternalService(dealerInstance)
checkIfInstanceWasConcurrentlyModified(dealerInstance, params.version)
dealerInstance.properties = params
saveUpdatedInstance(dealerInstance)
redirectToAfterUpdate(dealerInstance)
}
}
}