Cancel GWT-Event for following Handlers - events

I want to cancel an event for the following handlers. The sample-class below shows, what I try. Altough the keyevent is canceled for the textbox, the second handler is still called. the order of the handlers is correct. i can prove that Handler1 is called before Handler2. in this sample-class I could use a flag, but in my real class, the handlers and the textbox are seperated, so flags would be a problem. any ideas?
public class EventTestTextBox extends TextBox {
public static class Handler1 implements KeyUpHandler {
#Override
public void onKeyUp(KeyUpEvent event) {
if (event.isShiftKeyDown()) {
event.preventDefault();
event.stopPropagation();
((TextBox)event.getSource()).cancelKey();
}
}
}
public static class Handler2 implements KeyUpHandler {
#Override
public void onKeyUp(KeyUpEvent event) {
Window.alert("should not appear if shift-key is down.");
}
}
public EventTestTextBox() {
super.addKeyUpHandler(new Handler1());
super.addKeyUpHandler(new Handler2());
}
}

event.stopPropagation() cancels event bubbling, i.e. prevents handlers on parent elements to be triggered. It does not prevent handlers on the same element to receive the event.

I have exactly the same question as you. Did you manage to find a solution ?
I guess that the only solution would be to not register the event listener and let the handler1 dispatch (or not) to handler 2 instead.

Related

Apache Wicket: React on Ajax Request Before Model is Updated

I have a number of Wicket components on a page that use a PropertyModel to reflect properties of some beans. Using AjaxFormComponentUpdatingBehaviors, these components are automatically updated via Ajax when the user changes them.
When properties are changed, the beans I want to edit with my components fire PropertyChangeEvents that should trigger re-renders of certain components that listen to these events (implementing PropertyChangeListener):
Example:
User edits a TextField with a PropertyModel and an AjaxFormComponentUpdatingBehavior
An AJAX request is sent
Wicket dispatches the request to the AjaxFormComponentUpdatingBehavior
The behavior's onEvent updates the PropertyModel (unfortunately, this method is final)
The PropertyModel calls the backing bean's property setter
The backing bean fires and PropertyChangeEvent
Now I want all components listening for changes of the same backing bean to be notified
The behavior calls the abstract onUpdate, but now it's to late, the property change events are already handled.
Since my beans are not serializable, I cannot register the components permanently as event listeners. I either need to register proxy objects that somehow retrieve the component to notify, or register my components temporarily for the scope of the AJAX request.
What I would like to do is to hook into Wickets request cycle after the target page has been loaded but before the Ajax behavior updates the model, that would lead to the PropertyChangeEvent. Here I can register every component as a event listener on their backing beans (addPropertyChangeListener) so that they are notified if they need to be updated.
Then, in onEvent, each component can take measures to update itself using the AjaxRequestTarget if they received a PropertyChangeEvent before.
Finally, in onDetach, the components can unregister from their beans (removePropertyChangeListener).
Unfortunately, I found no built-in way to get a notification "on Ajax request". In my Ajax behavior's onUpdate methods, the model has already been updated and it is too late to register change listeners. I could implement my own behavior, but with the different component options (text fields, choice lists, etc.), this is quite an effort.
Did I miss something?
I don't quite understand exactly what you mean by "components registering as event listeners". Are you talking about registering IRequestCycleListeners?
Either way, perhaps Wicket's inter-component events can help you here. Every component implements the following interface:
public interface IEventSink
{
/**
* Called when an event is sent to this sink
*
* #param event
*/
void onEvent(IEvent<?> event);
}
You could subclass AjaxFormComponentUpdatingBehavior to fire an event after a model is updated like so:
public class AjaxUpdateEvent {
private final AjaxRequestTarget target;
public AjaxUpdateEvent(AjaxRequestTarget target) {
this.target = target;
}
public AjaxRequestTarget getAjaxRequestTarget() {
return target;
}
}
public class BeanModifiedEvent extends AjaxUpdateEvent {
private final Bean bean;
public BeanModifiedEvent(AjaxRequestTarget target, Bean theBean) {
super(target);
}
public Bean getBean() {
return bean;
}
}
public class CustomUpdatingBehavior extends AjaxFormComponentUpdatingBehavior {
protected abstract void onUpdate(AjaxRequestTarget target) {
Bean bean = getFormComponent().getModelObject();
getComponent().send(getComponent().getPage(), Broadcast.BREADTH, new BeanModifiedEvent(target, bean));
}
}
You can then catch the event in the required components and add them to the ajax request:
public class UserDetailsPanel extends Panel {
.....
#Override
public void onEvent(IEvent event) {
if(event.getPayload() instanceof BeanModifiedEvent) {
// if(whatever) to control whether to add or not
AjaxRequestTarget target = ((BeanModifiedEvent) event.getPayload()).getAjaxRequestTarget();
target.add(...);
}
}
Event doc:
17.2, "Wicket events infrastructure" section
18.3, "Built-in AJAX behaviors" section
You can override #getUpdateModel() to return false, then in #onUpdate() do whatever you want before calling getFormComponent().updateModel().
You could be overriding onModelChanging of each component you are using and firing your PropertyChangeEvent there. According to the documentation onModelChanging is called before
the model is changed.
#Override
protected void onModelChanging() {
super.onModelChanging();
oldModelObject = yourComponent.getModelObject();
//fire PropertyChangeEvent
}
This is what I came up with in the end.
I subclassed IContextProvider<AjaxRequestTarget, Page> to create a custom provider for AjaxRequestTarget objects. When an AjaxRequestTarget is requested, I broadcast it to the component tree using Wicket's event mechanism.
public class BroadcastingAjaxRequestTargetProvider implements IContextProvider<AjaxRequestTarget, Page> {
private final IContextProvider<AjaxRequestTarget, Page> parent;
public BroadcastingAjaxRequestTargetProvider(IContextProvider<AjaxRequestTarget, Page> parent) {
this.parent = parent;
}
#Override
public AjaxRequestTarget get(Page page) {
AjaxRequestTarget target = parent.get(page);
page.send(page, Broadcast.BREADTH, new AjaxRequestBegin(target));
return target;
}
}
The class AjaxRequestBegin is just a small payload object encapsulating the AjaxRequestTarget.
I register this provider in my Wicket application's init() method:
setAjaxRequestTargetProvider(new BroadcastingAjaxRequestTargetProvider(getAjaxRequestTargetProvider()));
Now each component gets notified when an AJAX request is handled, before Wicket dispatches it to a component or behavior. A component can override onEvent to register a PropertyChangeListener for the request:
public void onEvent(IEvent<?> event) {
final Object payload = event.getPayload();
if (payload instanceof AjaxRequestBegin) {
final AjaxRequestTarget target = ((AjaxRequestBegin) payload).getTarget()
AjaxPropertyChangeListener listener = new AjaxPropertyChangeListener(target);
target.addListener(listener);
getBean().addPropertyChangeListener(listener);
}
}
private class AjaxPropertyChangeListener implements PropertyChangeListener, AjaxRequestTarget.IListener {
private final AjaxRequestTarget target;
public AjaxPropertyChangeListener(AjaxRequestTarget target) {
this.target = target;
}
#Override
public void propertyChange(PropertyChangeEvent event) {
target.add(MyComponent.this);
}
#Override
public void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target) {
}
#Override
public void onAfterRespond(Map<String, Component> map, IJavaScriptResponse response) {
getBean().removePropertyChangeListener(this);
}
}
Note that AjaxPropertyChangeListener also implements AjaxRequestTarget.IListener to unregister itself after the AJAX request has been completed.

GwtEvent does not get dispatched

I have an application that uses EventBus for dispatching Application wide events. For some reason if I call one event and then try to register handler immediately before firing the second event it does not get dispatched. Is there any other way to dynamically register handlers on event ? Please see the code below:
MyEntry.java
package com.example.eventbus.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
public class MyEntry
implements EntryPoint {
SimpleEventBus bus;
#Override
public void onModuleLoad() {
bus = new SimpleEventBus();
fireEvent1();
}
private void fireEvent1(){
bus.addHandler(MyEvent1.TYPE,new MyEvent1.Handler() {
#Override
public void onEvent1(MyEvent1 event) {
RootPanel.get().add(new Label("Event1"));
fireEvent2();
}
});
bus.fireEvent(new MyEvent1());
}
private void fireEvent2(){
bus.addHandler(MyEvent2.TYPE,new MyEvent2.Handler() {
#Override
public void onEvent2(MyEvent2 event) {
RootPanel.get().add(new Label("Event2")); //!!!!!This line is not being called
}
});
bus.fireEvent(new MyEvent2());
}
}
MyEvent1.java
package com.example.eventbus.client;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
public class MyEvent1 extends GwtEvent<MyEvent1.Handler>{
public static Type<MyEvent1.Handler> TYPE=new Type<MyEvent1.Handler>();
#Override
public com.google.gwt.event.shared.GwtEvent.Type<Handler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(Handler handler) {
System.out.println("dispatch Event1");
handler.onEvent1(this);
}
public interface Handler extends EventHandler{
public void onEvent1(MyEvent1 event);
}
}
MyEvent2.java
package com.example.eventbus.client;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
public class MyEvent2 extends GwtEvent<MyEvent2.Handler>{
public static Type<MyEvent2.Handler> TYPE=new Type<MyEvent2.Handler>();
#Override
public com.google.gwt.event.shared.GwtEvent.Type<Handler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(Handler handler) {
System.out.println("dispatch Event2"); //!!!! This line is never called
handler.onEvent2(this);
}
public interface Handler extends EventHandler{
public void onEvent2(MyEvent2 event);
}
}
The issue is that while an event bus is firing events, it queues up any added or removed handler, and deals with them when it is finished. The idea is that if you only start listening to something while another event is still going off, then you are not interested for this round of events, but for the next round. The same thing happens when removing a handler - you will still hear about events that are still in the process of happening, but after the event bus is finished firing, it will deal with removal.
Try changing your code to wire up both handlers before firing anything, then try firing one event to the other.
Let me suggest to take a try to a new feature in gwtquery called 'custom events'.
We have introduced the new events mechanism during the recent GWT.create conferences, take a look to this slide (use arrows to move between slides).
You can attach custom events to any element in the DOM tree, widgets, and the window element.
Then you can trigger the event from any point in your code and every handler with this custom event name will be executed.
The main goal of the gQuery approach apart from being simpler, is that it performs significantly better than gwt eventbus, since the native browser selects in a low-level way which handlers to execute instead of using javascript to loop over a list, and execute handlers sequentially.
You might want to check out GWTP #ProxyEvent:
So when should you use #ProxyEvent? Basically, you use it every time that an event should have the ability to “wake up” your presenter. That is, whenever the presenter should be notified of an event even before it is first instantiated.

OnLoad Event of GWT Widget like TextBox, TextArea

I want to catch the onLoad Event of TextBox. But I am not finding any handler through which I can call it. GWT provides LoadHandler for the same purpose. But I don't know how should I instantiate the Load Event from TextBox.
Any help would be appreciable!!!
TextBox extends ValueBoxBase which has a protected method called onLoad().
All you have to do is the following
public class MyTextBox extends TextBox
{
#Override
protected void onLoad() {
//Do your stuff
}
}
It seems you are looking for addAttachHandler() .
If you are designing an custom textbox implement the interface HasAttachHandlers .
textBox.addAttachHandler(new Handler() {
#Override
public void onAttachOrDetach(AttachEvent event) {
if (event.isAttached()){
doMyOnLoadMethod();
}
}
});

GWTP: event sent once but received (handler) twice

On GWTP I am sending a UpdateDiagramBoxEvent with the code below, but the handler is executed twice. In other words, I can see that the sendUpdateDiagramBoxEvent() is executed only once, but it is received twice. The same is happening with many other events on my code. Any ideas of what is wrong, and how can I avoid this behaviour? THANKS.
Receive event
UpdateDiagramBoxHandler updateDiagramBoxHandler = new UpdateDiagramBoxHandler() {
#Override
public void onUpdateDiagramBox(UpdateDiagramBoxEvent event) {
doSomething();
}
};
Send event
EventUtil.sendUpdateDiagramBoxEvent(CellTableManager.this.eventBus,
BasicConstants.EventSubscriptors.VIEW, 0,
BasicConstants.EditableTableFields.DIAGRAMTYPE,
ClientState.getCurrentDiagramType().name());
public static void sendUpdateDiagramBoxEvent(final EventBus eventBus,
final BasicConstants.EventSubscriptors recipient,
final int index, final BasicConstants.EditableTableFields field,
final String value){
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
UpdateDiagramBoxEvent updateDiagramBoxEvent =
new UpdateDiagramBoxEvent(transactionNumber, recipient,
field.toString(), value, index);
eventBus.fireEvent(updateDiagramBoxEvent);
}
});
}
Register event handler (from MyProjectPresenter.java)
#Inject PlaceManager placeManager;
#Override
protected void onBind() {
[...]
registerHandler(getEventBus().addHandler(UpdateDiagramBoxEvent.getType(),
updateDiagramBoxHandler));
}
It generally means that you simply registered your event handlers twice.
Is this GWTP and if so how are you registering your events/handlers? I seem to recall there is a pitfall that you can use either #ProxyEvent or addRegisteredHandler() but not both, or you will receive the events twice.
Hope that helps.
Cheers,
Or the bean in question might not be singleton.

Is transactional #observes working for fired events on JBoss AS 7?

In order to use events only listened if a transaction succeeds or fails, I'm following the given doc about transactional observers :
http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html_single/#d0e4075
... but cannot manage to make my code work on JBoss AS7.
Here's my EJB:
#LocalBean
#Stateful
#TransactionAttribute(TransactionAttributeType.NEVER)
public class MyController
{
#Inject
private transient Event<MyEvent> myEventLauncher;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void save()
{
myEventLauncher.fire(new MyEvent());
}
#AfterCompletion
protected void afterSave(boolean isCommitted)
{
// do stuff
}
}
And here my basic listener:
public class MyHandler
{
protected void listenMyEvent(#Observes(during=TransactionPhase.AFTER_SUCCESS) MyEvent event)
{
// do stuff
}
protected void listenMyEvent2(#Observes(during=TransactionPhase.AFTER_FAILURE) MyEvent event)
{
// do stuff
}
}
I can say I'm in a transaction when the event is fired, because the afterSave method of the EJB is called. Alas, the methods listenMyEvent and listenMyEvent2 are always called both, like if I was not in a transactional context.
I tried the same code on GlassFish 3 and it perfectly works, so I guess there is a problem with JBoss AS 7, but I cannot find any bug report about it.
Well, as my current tests made me think that transactional observers are not working in JBoss AS 7, I managed to do a workaround I gave here for people who are interested.
First, we need qualifier annotations: Immediate, AfterFailure and AfterSuccess.
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.PARAMETER })
public #interface AfterFailure
{}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.PARAMETER })
public #interface AfterSuccess
{}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.PARAMETER })
public #interface Immediate
{}
Also, three basic AnnotationLiteral to create in runtime instances of this three annotations.
Then, we need a encapsulator for our true events, that I named SpecialEvent.
public class SpecialEvent
{
private Object event; // the real event you want
public SpecialEvent(Object event)
{
super();
this.event = event;
}
public Object getEvent()
{
return event;
}
}
And at last, an observer for this special event and an interceptor for classes where you want to fire this kind of events (full explanation below).
#RequestScoped
public class SpecialEventObserver
{
#Inject
private Event<Object> anyEventFirer; // firer for real events
private List<Object> events; // queued events
public SpecialEventObserver()
{
events = new ArrayList<Object>();
}
// remove all queued events
public void reset()
{
this.events.clear();
}
public void fireAfterFailureEvents() throws Exception
{
this.fireAllEventsOnce(new AfterFailureLiteral());
}
public void fireAfterSuccessEvents() throws Exception
{
this.fireAllEventsOnce(new AfterSuccessLiteral());
}
protected void listenSpecialEvent(#Observes SpecialEvent specialEvent)
{
Object event = specialEvent.getEvent();
this.events.add(event);
this.fireEvent(event, new ImmediateLiteral());
}
protected void fireAllEventsOnce(Annotation qualifier) throws Exception
{
try
{
for (Object event : this.events)
{
this.fireEvent(event, qualifier);
}
}
catch (Exception e)
{
throw e;
}
finally
{
this.events.clear();
}
}
protected void fireEvent(Object event, Annotation qualifier)
{
Event eventFirer = anyEventFirer.select(event.getClass(), qualifier);
eventFirer.fire(event);
}
}
#Interceptor
#LocalInterception
public class MyInterceptor implements Serializable
{
#Inject
private SpecialEventObserver specialEventObserver;
#AroundInvoke
public Object intercept(InvocationContext ic) throws Exception
{
specialEventObserver.reset();
try
{
// call the real method
Object proceedResult = ic.proceed();
// real method succeeded, fire successful events
specialEventObserver.fireAfterSuccessEvents();
return proceedResult;
}
catch (Exception e)
{
// real method failed, fire failed events
specialEventObserver.fireAfterFailureEvents();
throw e;
}
}
}
The mechanism is quite simple:
When you want to fire an event, fire a SpecialEvent that hold the true event.
The SpecialEventObserver will catch any SpecialEvent and will immediately fire your own event with an Immediate qualifier. It will also queue the events for the after completion part.
At the end of your own method call (ic.proceed in the interceptor), MyInterceptor will ask the SpecialEventObserver either to fire again all events with a AfterFailure qualifier or a AfterSuccess qualifier, depending of the success of your method.
In place of #Observes(during=...), your own observers have to observe events with the right qualifier, like #Observes #Immediate, #Observes #AfterFailure or #Observes #AfterSuccess.
The behavior is not exactly the one that provides the native #Observes(during=...). The after completion part is not based on the transaction state, but on your own method call success:
In JaveEE6, transactional observers on after success or after failure phases must be immediately called if you're not in a transaction, like a IN_PROGRESS would do.
In this workaround, observers on after success or after failure phases will always be called at the end of the method, and only if it succeeded or failed.
This works with version 7.1.0.Final which is supposedly (-> with Jboss you never know) fully Java EE compliant. Also your bean is not thread-safe as it uses list instead of a concurrent queue.
Your observer methods need REQUIRES_NEW, as stated here :
http://www.seamframework.org/Documentation/WhyIsThereNoActiveTransactionInMySFSBTransactionalObserver

Resources