mikołak
mikołak

Reputation: 9705

Instantly synchronizing two tables in Vaadin

In my Vaadin UI, I have the following scenario:

Table sketch

In other words, there are two tables:

The final requirement precludes the tables having the same Container (in my understanding, which might be wrong).

What I've done currently is that I attach an ItemSetChangeListener and a ValueChangeListener, and use the events to update the data accordingly.

Here's the current crude implementation (in Scala actually, but I hope it's readable enough, if not, please comment) :

class DataTableSynchronizer(val master: Table, val slave: Table) extends ItemSetChangeListener with ValueChangeListener {

  def init():Unit = {
    master.addItemSetChangeListener(this)
    containerMaster.addListener(this.asInstanceOf[ValueChangeListener])

  }

  private def containerOf(t: Table) = t.getContainerDataSource().asInstanceOf[IndexedContainer]

  private def containerMaster = containerOf(master)

  private def containerSlave = containerOf(slave)

  override def containerItemSetChange(event: ItemSetChangeEvent) {
    //handling 
    //remove all items that have been deleted
    for(toDel <- containerSlave.getItemIds().filterNot(containerMaster.containsId(_))) {
      containerSlave.removeItem(toDel)
    }

    //add new items to the start
    for(toAdd <- containerMaster.getItemIds().filterNot(containerSlave.containsId(_))) {
      containerSlave.addItem(toAdd)
    }
    slave.validate();
  }

  override def valueChange(event: ValueChangeEvent) = {
      updateValuesInResults()
  }

  private def updateValuesInResults(): Unit = {
    //update all values in the "slave" table from the "master" table
    for((itemData,itemResults) <- containerMaster.getItemIds().map(id => (containerMaster.getItem(id),containerSlave.getItem(id)))) {
      for(propId <- itemData.getItemPropertyIds()) {
        itemResults.getItemProperty(propId).asInstanceOf[Property[Any]].setValue(itemData.getItemProperty(propId).getValue().asInstanceOf[Any])
      }
    }
  }

}

However, my problem is that I need the data to be synchronized continuously, as the user types, which is not happening due to the relevant events being sent only after some operation completes (a row is added, etc.).

How do I solve this, i.e. how do I enforce events being emitted often enough to enable continuous synchronization? The only idea I had was to use an ActionListener mapping all the keys, but that screams "abuse".

Note: I realize doing this through the server-side is less efficient, but this is not a concern in my case. However, client-side-based answers are OK as well, of course.

Upvotes: 2

Views: 857

Answers (1)

Ingo Kegel
Ingo Kegel

Reputation: 48070

You can set the TextChangeEventMode of the editor to EAGER and process single keystrokes in the event listener:

    TextField textField = ...;
    textField.setTextChangeEventMode(TextChangeEventMode.EAGER);
    textField.addTextChangeListener(new TextChangeListener() {
        @Override
        public void textChange(TextChangeEvent event) {
            String text = event.getText();
            // sync with other component
        }
    });

Upvotes: 3

Related Questions