With datasource listeners it's possible to receive notifications about changes in data source states and entity instances located inside them.
To register listeners, the Datasource.addListener()
, Datasource.removeListener()
methods are used. Below is an example of registering a listener in a screen controller:
@Inject private Datasource<Customer> customerDs; ... public void init(Map<String, Object> params) { ... customerDs.addListener(new DatasourceListener<Customer>() { // listener methods implementation }); }
There are two listener interfaces of datasources: DatasourceListener
and CollectionDatasourceListener
. The first can be used for registration in any of datasources, the second – only in those implementing CollectionDatasource
. Typically, in practice, it's not necessary to receive all notifications from a listener. That's why it is convenient to
use class-adapters, DsListenerAdapter
and CollectionDsListenerAdapter
, instead of implementation of listener interfaces, which contain empty implementations of all methods of corresponding interfaces.
DatasourceListener
methods are provided below:
-
valueChanged()
– declaration of this method is inherited from the base interface,ValueListener
. This listener method is invoked if an attribute value of some entity that is currently located in the source has changed. The modified instance itself, the name of changed attribute, old and new values are passed into the method.valueChanged()
notification can be used to respond to user changes in an entity from the UI, i.e., editing input fields. In the example below, a hypothetical method,updateSettings()
, will be invoked when the value of theactive
attribute is changed, and a new attribute value will be passed into this method:@Inject private Datasource<Customer> customerDs; public void init(Map<String, Object> params) { ... customerDs.addListener(new DsListenerAdapter<Customer>() { @Override public void valueChanged(Customer source, String property, Object prevValue, Object value) { if ("active".equals(property)) { boolean active = BooleanUtils.isTrue((Boolean) value); // converting null to false updateSettings(active); } } }); }
-
itemChanged()
– is invoked when a selected instance returned by thegetItem()
method is changed.For
Datasource
, it happens when another instance (ornull
) is set withsetItem()
method.For
Below is an example of theCollectionDatasource
, this notification is invoked when a selected element is changed in a linked visual component. For example, it may be a selected table row, tree element or item in a drop-down list.itemChanged()
notification to control the state of an action of the table:@Inject protected CollectionDatasource<Customer, UUID> customersDs; @Named("customersTable.remove") protected RemoveAction removeAction; public void init(Map<String, Object> params) { ... customersDs.addListener(new DsListenerAdapter<Customer>() { @Override public void itemChanged(Datasource<Customer> ds, Customer prevItem, Customer item) { removeAction.setEnabled(canCustomerBeDeleted(item)); } }); }
-
stateChanged()
– is invoked when a state of the data source is changed. The data source can be in one of three states corresponding to theDatasource.State
enumeration:-
NOT_INITIALIZED
– source has just been created. -
INVALID
– the whole DsContext, which this source is related to, is created. -
VALID
– data source is in working state:Datasource
contains an entity instance or null,CollectionDatasource
– collection of instances or an empty collection.
Receiving a notification about changes in source state may be important for complex editors, which consist of several frames where it is difficult to trace the moment of putting an edited entity into the source. In this case,
stateChanged()
notification for the delayed initialization of certain screen elements can be used:@Inject protected CollectionPropertyDatasourceImpl<CategoryAttribute, UUID> categoryAttrsDs; categoryAttrsDs.addListener(new DsListenerAdapter<CategoryAttribute>() { @Override public void stateChanged(Datasource ds, Datasource.State prevState, Datasource.State state) { if (state != Datasource.State.VALID) return; initDataTypeColumn(); initDefaultValueColumn(); } });
-
The CollectionDatasourceListener
interface adds one more method:
-
collectionChanged()
– is invoked when a entity collection, which is stored in the data source, is changed. One of the following type of changes is passed into the method:REFRESH
,CLEAR
,ADD
,REMOVE
,UPDATE
.Below is an example of a listener that invokes the recalculation of a journey cost in case of the address of a stop (the
Stop
entity) or the number of stops is changed:protected class StopDsListener extends CollectionDsListenerAdapter<Stop> { @Override public void valueChanged(Stop source, String property, Object prevValue, Object value) { // existing stop address changed if ("address".equals(property)) { fireRouteChanged(); } } @Override public void collectionChanged(CollectionDatasource ds, Operation operation) { // stop was added or removed fireRouteChanged(); } private void fireRouteChanged() { // journey route has changed, need to recalculate price, journey time, pickup time delay etc. } }