Widget notifying other widget(s) - gwt

How should widgets in GWT inform other widgets to refresh themselfs or perform some other action.
Should I use sinkEvent / onBrowserEvent?
And if so is there a way to create custom Events?

I have solved this problem using the Observer Pattern and a central Controller. The central controller is the only class that has knowledge of all widgets in the application and determines the way they fit together. If someone changes something on widget A, widget A fires an event. In the eventhandler you call the central controller through the 'notifyObservers()' call, which informes the central controller (and optionally others, but for simplicity I'm not going into that) that a certain action (passing a 'MyEvent' enum instance) has occurred.
This way, application flow logic is contained in a single central class and widgets don't need a spaghetti of references to eachother.

It's a very open ended question - for example, you could create your own static event Handler class which widgets subscribe themselves to. e.g:
Class newMessageHandler {
void update(Widget caller, Widget subscriber) {
...
}
}
customEventHandler.addEventType("New Message", newMessageHandler);
Widget w;
customEventHandler.subscribe(w, "New Message");
...
Widget caller;
// Fire "New Message" event for all widgets which have
// subscribed
customEventHandler.fireEvent(caller, "New Message");
Where customEventHandler keeps track of all widgets subscribing to each named event, and calls the update method on the named class, which could then call any additional methods you want. You might want to call unsubscribe in the destructor - but you could make it as fancy as you want.

So here is my (sample) implementation,
first let's create a new event:
import java.util.EventObject;
import com.google.gwt.user.client.ui.Widget;
public class NotificationEvent extends EventObject {
public NotificationEvent(String data) {
super(data);
}
}
Then we create an event handler interface:
import com.google.gwt.user.client.EventListener;
public interface NotificationHandler extends EventListener {
void onNotification(NotificationEvent event);
}
If we now have a widget implementing the NotificationHanlder, we can
trigger the event by calling:
((NotificationHandler)widget).onNotification(event);

Related

How can I refresh a Panel from another ListView in Apache Wicket?

I have a panel (say AlertPanel) which needs to be refreshed for some condition when a listView renders.
I am thinking to update the AlertPanel in onBeforeRender() lifecycle method of listview.
I have tried to override onBeforeRender() like this-
#Override
protected void onBeforeRender() {
super.onBeforeRender();
// update alert panel with some API of Component here
// I can get panel object like this 'this.getPage().get("alertPanel");'
}
Once I have this.getPage().get("alertPanel"), I don't know what API of org.apache.wicket.markup.html.panel.Panel to call so that I can refresh/repaint AlertPanel
If the rendering has started (and it seems it has - onBeforeRender()) then you won't be able to replace any components.
You should move your logic to the ACTION phase, e.g. onClick(), onSubmit(), etc. In such action method broadcast an event: send(getPage(), Broadcast.DEPTH, new SomeCustomEvent()). Then either in the AlertPanel's parent you should override #onEvent(IEvent) and when the event payload is SomeCustomEvent then do the replacement.
For more info read: https://ci.apache.org/projects/wicket/guide/7.x/single.html#_wicket_events_infrastructure
There are two ways:
1) the complex one: use listeners
2) or use method overriding, like this:
AlertPanel alertPanel = new AlertPanel();
alertPanel.setOutputMarkupId(true);
ListView list = new MyListView(){
#Override
protected onMyEvent(AjaxRequestTarget target){
target.add(alertPanel);
}
}
page.add(alertPanel,list);
onMyEvent() method of MyListView can be abstract and have to be called where you want to update the alertPanel inside of MyListView (e.g. when button pressed in some of rows)

how to stop firing unrelated event of event bus

My problem is with how to stop firing unrelated event of event bus. as I got this solution for Dialog box.
but it does not work in case of where one instance already initialize and try to create new instance of same class.
Just example: A below scroll panel has handler initialized. it used for document preview.
class TestScroll extends ScrollPanel
{
public TestScroll(){
}
implemented onload()
{
// eventBus.addHandler code here.
//here some preview related code
}
unload() method
{
//eventBus remove handler code
}
}
This preview has some data which contains some links that open different preview but with same class and different data structure,
Now The problem is like onUnload ( which contains code of remove handler) event does not load , because other panel opened. that does not mean previous panel unload.
So in that case, twice event handler registered. when one event fired then other event also fired.
Due to that, Preview 1 data shows properly, but after that Preview2 opened and when I close it, I find Preview1=Preview2.
so how can I handle such situation?
As per no of instance created each event fired. but I have to check some unique document id with if condition in event itself.
is there any other ways to stop unrelated event firing?
Edit:
public class Gwteventbus implements EntryPoint {
int i=0;
#Override
public void onModuleLoad() {
TestApp panel=new TestApp();
Button button=new Button("Test Event");
button.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
TestApp panel=new TestApp();
int j=i;
new AppUtils().EVENT_BUS.fireEventFromSource(new AuthenticationEvent(),""+(j));
i++;
}
});
panel.add(button);
RootPanel.get().add(panel);
}
}
public class AppUtils {
public static EventBus EVENT_BUS = GWT.create(SimpleEventBus.class);
}
public class TestApp extends VerticalPanel{
String testString="";
public TestApp( ) {
AppUtils.EVENT_BUS.addHandler(AuthenticationEvent.TYPE, new AuthenticationEventHandler() {
#Override
public void onAuthenticationChanged(AuthenticationEvent authenticationEvent) {
System.out.println("helloworld"+authenticationEvent.getSource());
}
});
}
}
These are wild guesses as it's difficult to really answer it without code and a clear description.
I'm guessing you have one eventbus for all the panels. So when you register a handler it is registered with that one eventbus. In case you fire an event from one of the panels to the eventbus all panels will receive the event.
To fix this you can either create a new eventbus per panel or check who fired the event with event.getSource().
If this doesn't make sense you probably are reusing a variable or use a static variable which actually should be a new instance or none static variable.
You can use the GwtEventService-Library to fire specific events over a unique domain and every receiver that is registered at this domain receives that events then. You can handle as many different events/domains as you want.
In order to remove a handler attached to the EventBus, you must first store a reference to the HandlerRegistration returned by the addHandler method:
HandlerRegistration hr = eventBus.addHandler(new ClickHandler(){...});
Then you can remove the handler with the removeHandler method:
hr.removeHandler();
A final note worth mentioning is that when using singleton views, like is typical with MVP and GWT Activities and Places, it is best practice to make use of a ResettableEventBus. The eventBus passed to an activity's start() is just such a bus. When the ActivityManager stops the activity, it automatically removes all handlers attached to the ResettableEventBus.
I would strongly recommend reading the GWT Project's documentation on:
Activities and Places
Large scale application development and MVP

GWT 2.4 customized ListBox doesn't fire Change event

I have added some extra functionality to the standard GWT ListBox by extending it like so:
public class FeatureListBox extends ListBox
{
public FeatureListBox()
{
}
public FeatureListBox(boolean isMultipleSelect)
{
super(isMultipleSelect);
}
public FeatureListBox(Element element)
{
super(element);
}
}
Nothing fancy here. However, the Change event is not firing now, or at least the handler (attached per below) is not getting invoked.
FeatureListBox listBox = new FeatureListBox();
listBox.addChangeHandler(new ChangeHandler()
{
public void onChange(ChangeEvent event)
{
// Do something here...
}
});
Any ideas why?
Either remove the no-argument constructor from FeatureListBox or call super() inside it, otherwise the initialization in the superclasses won't happen, which would probably result in what you're seeing.
The problem was in the way I was using my custom list box. In my application I wrap GWT Widgets around existing DOM elements on the page using the static wrap() methods of their widget classes in which the widgets get marked as attached, making them fire events. I didn't do that with my custom list box class originally, so I ended up implementing a static wrap() method similar to the one of the regular ListBox widget and using it in my code. Everything works like a charm now.

GWT : Do I make event and event handler class?

I have gwt-project that is comunication to database.
Application design mvp pattern and view has a input form, a grid and many buttons.
According to gwt tutorial, each event has a event class, a event handler class and initialize event handler class in presenter.
So, Do I make event and event handler class if the number of events are uncountable?
[Example package] :
src/com/example/event/${A Lot Of Event}
src/com/example/event/${A Lot Of Event Handler}
src/com/example/presenter/${A Presenter}
src/com/example/view/${A View}
I like to put the event handler (and optionally the has handlers interface, if you make one) as inner classes (okay, interfaces) of the event itself. Usually looks something like this:
public class MyAppEvent extends GwtEvent<MyAppEventHandler> {
//... event guts, dispatch, getAssociatedType, etc
public interface MyAppEventHandler extends EventHandler {
void onMyAppEventHappened(MyAppEvent event);
}
// and optionally, if you only register handlers through add methods
public interface HasMyAppEventHandlers {
void addMyAppEventHandler(MyAppEventHandler handler);
}
}

How to instantiate an Event Handler interface in GWT using uiBinder?

I'm trying to use a custom widget: gwtupload with it's custom handlers. The handlers are defined as interfaces, as in, Interface.OnCustomEventHandler and the method, according to the API, that I want to use is like this code, but I'm not sure how to implement this with uiBinder.:
void onCustomEvent (Interface interface)
Normally for uiBinder I use this code for the regular gwt widgets:
#Widget widget;
#UiHandler("widget")
void onClick(ClickEvent event){
//Handle the event processing here.
}
Presently, when I try this,
#UiHandler("widget")
void onCustomEvent(ICustomInterface customInterface){
...
I get this null pointer exception:
[ERROR] Generator 'com.google.gwt.uibinder.rebind.UiBinderGenerator' threw an exception while rebinding '...ViewImpl.ViewImplUiBinder'
java.lang.NullPointerException
Here is the new code I tried:
public class MUpld extends Composite {
private static MUpldUiBinder uiBinder = GWT.create(MUpldUiBinder.class);
interface MUpldUiBinder extends UiBinder<Widget, MUpld> {
}
#UiField MultiUploader uploader;
public MUpld() {
final IUploader.OnFinishUploaderHandler onFinishUploaderHandler = new IUploader.OnFinishUploaderHandler() {
#Override
public void onFinish(IUploader iUploader) {
if (uploader.getStatus() == Status.SUCCESS){
System.out.println("In the onFinish method!");
}
}
};
initWidget(uiBinder.createAndBindUi(this));
uploader.addOnFinishUploadHandler(onFinishUploaderHandler);
}
}
In the debugger, I saw the handler get attached to the uploader widget I defined, but then the current uploader became a different one once the code moved out of this class. I tried using the final modifier, as that is the only way I know to get a variable into an inner class, but gwt would complain with:
[ERROR] com.cdg.complexityCalculator.client.view.MUpld has no default (zero args) constructor.
To fix this, you can define a #UiFactory method on the UiBinder's owner, or annotate a constructor of MUpld with #UiConstructor.
I wasn't able to get either of those options to work, but I realized I had the last two lines of code switched, so I changed it to what I have now and the handler loaded up with the correct object.
Any ideas as to how to get this to work? Everything else is in place, I just need a way to capture this event after my servlet has finished processing.
When I changed the last two lines of code, the handler got loaded properly. Now the objects are being created with the handler binding to the correct object.
initWidget(uiBinder.createAndBindUi(this));
uploader.addOnFinishUploadHandler(onFinishUploaderHandler);
I had to wait until the uiBinder created the instance of the uploader widget, then I was able to add the handler to it.
One of the tricks I've learned is to add a handler in the constructor for a composite widget you create, that way it's more of an encapsulated component. It handles it's own events.