How can I refresh a Panel from another ListView in Apache Wicket? - 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)

Related

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.

In a GWT HTML widget displaying complex HTML, how do I add an event handler for specific subelements?

I'm optimizing a GWT application that previously used a variety of nested panels to work with DIVs and Spans. I generate the entire table as a single SafeHtml object and then assigning it into a single SafeHtml widget.
I now want to be able to track mouseover/mouseout events at the level of the specific 'cell' spans rather than the entire table, but I'm not sure how to do this.
If I add a handler to the HTML widget itself, I'll get events sourced at various elements.
Since 2.0 there is quite a simple way to do it.
For example if you HTML code is contained in some kind of widget (HTMLPanel or HTML), you can calladdDomHandler(<handler>,<eventtyoe>) on that widget, so you will receive events from inner html.
For example if you have a bunch of anchors inside HTMLPanel and you want to know which one was clicked you can do something like this:
panel.addDomHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Element element= event.getNativeEvent().getEventTarget().cast();
if(element.getTagName().equals("A")) {
AnchorElement anchor = element.cast();
Window.alert("Anchor with href " + anchor.getHref() + " was clicked");
}
}
}, ClickEvent.getType());
Since you want to track mouseover/out events you will have to use 2 different dom handlers, find out cell you need when event is fired and then change its state.
The way to approach this is:
Find the element you need with one of the DOM methods, like DOM.getElementById(..) or any other means. View Widget.getElement() etc.
Call DOOM.sinkEvents(element,eventBits) or DOM.sinkBitlessEvent(element,eventName) and pass the required events you want to sink in form of a bitmask, like Event.MOUSEEVENTS or using a named event like click or touchstart if using the second method.
set and EventListener on the element, by calling DOM.setEventListerner(element,eventListener) like so:
DOM.setEventListener( element, new EventListener()
{
#Override
public void onBrowserEvent( Event event )
{
if ("click".event.getType()) {
// ..do stuff..
}
}
} );
Only events you've specified in step 2 will be fired to your EventListener, so you need to only handle those.

GWT adding a ClickHandler to a DOM element

lets say i have a custom widget which has a ClickHandler. Here's the example:
public class TestWidget extends Composite {
private static TestWidgetUiBinder uiBinder = GWT
.create(TestWidgetUiBinder.class);
interface TestWidgetUiBinder extends UiBinder<Widget, TestWidget> {
}
#UiField
Button button;
public TestWidget(String firstName) {
initWidget(uiBinder.createAndBindUi(this));
button.setText(firstName);
}
#UiHandler("button")
void onClick(ClickEvent e) {
Window.alert("Hello!");
}
}
When i try to add this Widget like this:
TestWidget testWidget = new TestWidget("myTestWidget");
RootPanel.get().add(testWidget);
everything is fine. If i click on my button i get the message i expect.
However if i add it like this:
TestWidget testWidget = new TestWidget("myTestWidget");
RootPanel.getBodyElement().appendChild(testWidget.getElement());
my click event is not being fired. I'm struggeling to understand why.
It would be nice if someone could explain this to me or link me to an resource where i can read this up. Finally i would like to know if it is possible to add the clickhandler afterwards i appended the child event and if that way is recommended. Thanks it advance for help.
kuku
When you call add(), Widget.onAttach() is called on the widget that is being added to the panel. onAttach does some work to register the widget to receive events. appendChild() simply attaches one DOM element to another and does nothing else. You should be able to get events working in the second case by doing this:
Element element = testWidget.getElement();
RootPanel.getBodyElement().appendChild(element);
DOM.sinkEvents(element,
Event.getTypeInt(ClickEvent.getType().getName())
| DOM.getEventsSunk(element);
However, I haven't tested this and I wouldn't recommend that you use it in a real application. Using add() is definitely preferred, using appendChild() in this way has no advantages and may lead to unexpected behaviour.

How to group gwt composite widgets change events as one change event

If i have a GWT composite widget with three text boxes like for SSN, and i need to fire change event only when focus is lost from the widget as a whole, not from individual text boxes how to go about doing that?
If you want just the event when your whole widget loses focus (not the text boxes), then make the top level of your widget be a FocusPanel, and expose the events that it gives you.
You need to implement the Observer Pattern on your composite, and trigger a new notification everytime:
the focus is lost on a specific text box AND
the focus was not transferred to any of the other text boxes.
Couldn't you use a timer? On lost focus from a text box, start a 5ms (or something small) timer that when it hits, will check focus on all 3 TextBox instances. If none have focus, then you manually notify your observers. If one has focus, do nothing.
Put this in your Composite class:
private Map<Widget, Boolean> m_hasFocus = new HashMap<Widget, Boolean>();
And then add this to each one of your TextBox instances:
new FocusListener() {
public void onFocus(Widget sender) {
m_hasFocus.put(sender, Boolean.TRUE);
}
public void onLostFocus(Widget sender) {
m_hasFocus.put(sender, Boolean.FALSE);
new Timer() {
public void run() {
for (Boolean bool : m_hasFocus.values()) {
if (bool) { return; }
}
notifyObservers();
}
};
}
};

Widget notifying other widget(s)

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);