I’ve created an table containing data that can be in a user-defined sequence. To allow the user to move the items up and down the list, I’ve added a couple of up down buttons to the bottom of the table.
I’ve attached a sequence number to each record in the table, so all I do is flip the numbers to swap two records over in the table.
The problem is that I can’t figure out how to make the table redraw once I’ve executed the code that changes the sequence.
I thought that refreshing the datasource would update the table, but it seems i have to commit the change then come back into the screen to see the changes.
Is there some way of forcing the table to redraw to reflect the change in order?
Here’s the code I’m using to try to flip the order.
/**
* This method is invoked when the user presses the up button on the table.
* If the item is not at the top of the table then move it up one place.
*/
public void up() {
StageTemplate currentlySelectedStageTemplate = stageTemplatesTable.getSingleSelected();
assert currentlySelectedStageTemplate != null;
if (currentlySelectedStageTemplate.getSequenceOrder() > 1
&& stageTemplatesDs.getItems().size() > 1) {
// Swap orders with the record above it.
StageTemplate previousStageTemplate = stageTemplatesDs.getItems()
.stream()
.filter(stageTemplate -> stageTemplate.getSequenceOrder()
== currentlySelectedStageTemplate.getSequenceOrder() - 1)
.findFirst()
.get();
previousStageTemplate.setSequenceOrder(previousStageTemplate.getSequenceOrder() + 1);
stageTemplatesDs.modifyItem(previousStageTemplate);
currentlySelectedStageTemplate.setSequenceOrder(currentlySelectedStageTemplate.getSequenceOrder() - 1);
stageTemplatesDs.modifyItem(currentlySelectedStageTemplate);
stageTemplatesDs.refresh();
}
}
Running this through the debugger shows that the sequences are changed correctly; it’s just that the table doesn’t appear to refresh.
Now you can update the table only by removing all items from the datasource and adding them again in different order. For example:
public void onUpBtnClick() {
Customer current = customersDs.getItem();
if (current == null || current.getSeqOrder() == 0)
return;
Optional<Customer> prevOpt = customersDs.getItems()
.stream()
.filter(customer -> customer.getSeqOrder() == current.getSeqOrder() - 1)
.findFirst();
if (!prevOpt.isPresent())
return;
int currOrder = current.getSeqOrder();
current.setSeqOrder(currOrder - 1);
prevOpt.get().setSeqOrder(currOrder);
refreshTable(current);
}
public void onDownBtnClick() {
//...
}
private void refreshTable(Customer current) {
List<Customer> items = new ArrayList<>(customersDs.getItems());
customersDs.clear();
items.sort(Comparator.comparing(Customer::getSeqOrder));
for (Customer item : items) {
customersDs.includeItem(item);
}
customersTable.setSelected(current);
((DatasourceImplementation) customersDs).setModified(false);
}
I know it looks ugly, and we are going to address this issue in a future major version.
The whole sample project is attached. order-table.zip (82.6 KB)
Oh, of course if you want to persist the seqOrder attribute, you don’t need this line at all - the datasource becomes modified as soon as you change an entity contained in it.
In my example it’s a non-persistent attribute, so there was nothing to save.
Yes, all operations on collectionContainer.getMutableItems() list are reflected in UI.
For nested property containers you may also want to use getDisconnectedItems() to filter/sort items in UI without affecting the underlying connection.