I want to create custom events and fire them in some part of the view such that some other part of the view is updated/removed/refreshed.
I have tried by extending the Component.Event and Component.Listener but it doesn't work. I think that events and listeners mustbe limited to the same component instance.
Can this be done with Vaadin 7?
Basically I want to decouple my views and provide easy communication between components. I'm also using Spring with Vaadin. If you have better ideas beside the Observer pattern I would also appreciate it.
Thank you
What you need:
1. A component that fires the event
2. A custom event class
3. A listener interface
4. And a listener implementation
Component from 1 need to have an list of event-listeners, and the methods: addListener
; removeListener
; and dispatchEvent
. The dispatchEvent
-method will iterate through the list of event-listeners and execute some method (see 4: the listener implementation). That method has as argument an event-object (see 2: the custom event class).
Essential code for 1:
protected List<MyListener> listeners;
protected synchronized void dispatchEvent(MyEvent event) {
if (listeners != null) {
for (MyListener listener : listeners) {
listener.myMethod(event);
}
}
}
public synchronized void addListener(MyListener listener) {
if (listeners == null) {
listeners = new ArrayList<MenuListener>();
}
listeners.add(listener);
}
public synchronized void removeListener(MyListener listener) {
if (listeners == null) {
listeners = new ArrayList<MyListener>();
return;
}
listeners.remove(listener);
}
Essential code for 2:
public class MyEvent {
protected String eventType;
public MyEvent(String eventType) {
this.eventType = eventType;
}
//getters and setters
}
Essential part for 3:
public interface MyListener {
public void doSomething(MyEvent event);
}
Code for 4 (listener implementation)
public class MyImplementation implements MyListener {
@Override
public void doSomething(myEvent event) {
//do something concretes here
}
}
How the code flow works:
The dispatcher class will, after some interaction, "announce" to every event-listener that something has happened.
dispatchEvent(new MyEvent("ADD_USER"));
In a class you want to receive the event you need to instantiate the dispatcher class and listener implementation class, and add the listener to the dispatcher's list:
MyDispatcher disp = new MyDispatcher();
MyImplementation myImpl = new MyImplementation();
// Then add the event-listener to the dispatcher:
disp.addListener(myImpl);
Sure, some of these classes can be inner classes, and the code could be simplified or extended, but this is the general idea. This is also just plain Java and has nothing Vaadin-dependent.
Actaully, there are some frameworks build on Vaadin to decouple your view and provide easy event based communication as you said. This approach is called MVP patter - Model view presenter and it provides a event driver
communication between components. There are som MVP Vaadin frameworks available at the time:
https://github.com/peholmst/MVP4Vaadin
https://github.com/panter/org.vaadin.mvp
You can use EventRouter. But I do not use it.
Or You can use ObjectProperty.
This object can firing event when value is changed.
For example:
public class MyApplication extends UI{
private ObjectProperty<MyState> myState= new ObjectProperty<MyEvent>(new MyState());
public ObjectProperty<MyState> getMyState(){return myState;}
}
public class MyComponent1 extends VerticalLayout{
public MyComponent1(){
//create UI
....
updateData();
Property.ValueChangeListener updateListener = new Property.ValueChangeListener() {
@Override
public void valueChange(Property.ValueChangeEvent event) {
updateData();
}
};
MyApplication.getCurrent().getDispatcher().addValueChangeListener(updateListener);
}
private void updateData(){
MyState myState = MyApplication.getCurrent().getMyState().getValue();
//update this component with myState
}
}
public class MyComponent2 extends VerticalLayout{/*Similarly with Component1*/}