How to tell table to update when its data changes?

I’ve just completed the book tutorial. So I have a table backed by a data container. Now I want to modify the values in a column. My first try was to just iterate through the items in the data container, changing the bean values directly. But I didn’t see the table update. How do I tell the table that the datasource, or better yet, one column, has changed and it needs to resort/redraw?

Hi!

You containers Properties needs to emit ValueChangeEvents. See interface com.vaadin.Property.ValueChangeNotifier

cheers,
matti

If you do not change the beans directly but instead use the properties to change the value, the container will get the information that values have been updated.

Wouldn’t that be much slower? It would have to use the property for each row instead of doing them all at once by directly updating the values in the container, I think…

So you’re saying to implement ValueChangeNotifier. Then you would explicitly tell the table to add itself as a listener? What would the listener callback do? Refresh or redraw the table? But then why not do that directly? Perhaps you could point to an example; I haven’t found one in the forum or API code…

Here’s what I have working so far. This code is in MyTable, which subclasses Table. The datasource subclasses BeanItemContainer.


	public void updateMyValues() {
		for (Object itemId: this.getItemIds()) {
			Item item = getItem(itemId);
			MyItem si = (MyItem) ((BeanItem) item).getBean();
			si.update();
			item.getItemProperty("amount").setValue(si.getAmount());
		}
		sort();
	}

So I think that follows Artur’s suggestion of using the properties. Seems like a lot of indirection, though… I would think the container should just get an update request, then update all of its elements. So the question is how to have the Table notice when the container updates itself?

Hi there,

This is the method I added to my container base class to update items in a generic way (the base container extends BeanItemContainer):

	
	public void updateItem(Object itemId){
		if (this.containsId(itemId)){
			BeanItem newItem = new BeanItem(itemId);
			BeanItem oldItem = this.getItem(itemId);
			if (oldItem != null){
				for (Object property: getContainerPropertyIds()){
					oldItem.getItemProperty(property)
                               .setValue(newItem.getItemProperty(property).getValue());
				}
			}
		}
	}

This avoids the need for a sort, and allows the update of a single item (or collection, by extension).

HTH,

Damien

PS. Make sure you implemented equals and hashCode in the bean class…

I am working on a RowSetContainer implementation, and was successful with a data source implementing Container.ItemSetChangeNotifier. The table will add itself as a listener upon
the setContainerDataSource if the data sources implements that interface.

This is good for entire data set changes, but for a single item property, it will probably be more efficient to deal with the property change events/notifiers, but I haven’t tried this myself yet.


public class MyContainer implements Container, Container.ItemSetChangeNotifier {

   public void updateDate() {
       // do item updates
       notifyItemSetChange();
   }

    private void notifyItemSetChange() {
        ItemSetChangeEvent e = new ItemSetChangeEvent(){
            @Override
            public Container getContainer() {
                return RowSetContainer.this;
            }
        };
        for(ItemSetChangeListener l:itemSetChangeListeners){
            l.containerItemSetChange(e);
        }
    }

    @Override
    public void addListener(ItemSetChangeListener listener) {
        itemSetChangeListeners.add(listener);
    }

    @Override
    public void removeListener(ItemSetChangeListener listener) {
        itemSetChangeListeners.remove(listener);
    }

    private ArrayList<ItemSetChangeListener> itemSetChangeListeners = new ArrayList<ItemSetChangeListener>();
}

I’m sorry if I’ve misunderstood, but why doesn’t Property.setValue() work for you? If you iterate through the items in a table and modify the specified property using setValue(), the table should update accordingly.

Sorry for waking an old thread, but I was just looking for an answer to the question. Here’s a situation where I want to change values outside my UI classes:

I have a Table with stuff in it. Second column indicates process status. Below is a Button labeled “try to process”. This calls an external method with the bean from the row as a parameter. The beans status gets updated in the external processing service according to how far it goes.

I would like to be able to tell my table that the data has changed.

I’m also having trouble getting my head around this… Im trying to change the value of a table property and im getting a readonly exception. After stepping throught he code I do see the readOnly() method being called on the propery. But here is the scenerio Im trying to implement…

I have a table that is selectable(not editable). After selecting a row you press a button to see details on the row. This subwindow is editable and one of the values that is editable on this window is a value that is also in the selectable table. If that value is changed I want to change the value in the selectable table.

I’ve try tried everything I’ve found on the fourms short of just reloading the original table view which I think I may have to do… but, I wanted to know why I can’t do this.

So trying this


Item myitem = usertable.getItem(usertable.getValue());
					
myitem.getItemProperty("userType.displayValue").setValue(user);//fails with readonly exception

The above code throws a NestedProperty readonly exception.
also as a side question. I also tried to do this


Item myitem = usertable.getItem(usertable.getValue());
usertable.getContainerProperty(myitem, "userType.displayValue").setValue(user);	

the above code throws a null pointer… when I step through the code ‘myitm’ isn’t found in the container, yet I find it when calling usertable.getItem(…) can some explain why that is?

Thanks

I think I found a better way of doing it.

Lets say I have bean item container for table of beans Dummy

public class DummyTable extends Table{

private static final BeanItemContainer<Dummy> dummyContainer = new BeanItemContainer<Dummy>(Dummy.class);


.......

public BeanItemContainer<Dummy> getDummycontainer() {
		return dummyContainer ;
	}
}

The way to update specific item

DummyTable dummyTable = new DummyTable();

… logic to add bean items in container

          [code]
    //below method should be calledc whenever item is changed in table through form submit
                 public updateItem(){
                                     Object itemId =dummyTable.getValue();
                                     //get index of item
				int index = dummyTable.getDummycontainer().indexOfId(itemId); 
				dummyTable.getDummycontainer().removeItem(itemId);

                                     //update item at given index..this helps to place new item at current position.
                                    dummyTable.getDummycontainer().addItemAt(index, newDumbObject);
                       }

[/code]

//The above method not only updates the table with new object at current position but also avoids the overhead of looping through itemproperties and set the values

The fact of the matter is that Vaadin should have a mechanism whereby you can change the underlying data without going through Vaadin’s abstractions. This happens all the time. As far as binding to Beans is concerned, the JavaBeans spec has awareness of events and defines how beans can post property change events. Vaadin should respect property change events produced by beans and update its bean-bound controls accordingly.

Does Vaadin have this capability?

Short of that, our programs will reinvent the wheel by listening into the beans themselves and telling the table to update. In the simple implementation, they will just replace the container, which will reset the table’s settings, like column order, column sizes, and the rest.

Push?

https://vaadin.com/book/vaadin7/-/page/advanced.push.html

Hi My code is as follows

I have a notes table and i want to update the table every 2 sceonds so that concurrent users can see the added notes for a spcific object.

I have refresher which runs and it doesnt seem to be getting the updates. But when the refresh button is clicked I could see the added notes.

When User A adds a note, user A can see the added notes in the table. But User B cannot see, he simply has to click refresh to see the new notes added by A.

the code in the addnotespopover is this.
VaadinSession.getCurrent().lock();
NoteResponse noteResponse = (NoteResponse) response.getData();
Note newNote = (Note) noteResponse.getNote();
mainTable.getContainerDataSource().addItem(newNote);
mainTable.setSortContainerPropertyId(“created”);
mainTable.sort();
mainTable.refreshRowCache();

finally {
VaadinSession.getCurrent().unlock();
}

This is the method for the refresher
if (VaadinSession.getCurrent().getAttribute(FUser.class) != null) {
final Refresher refersher = new Refresher();
refersher.setRefreshInterval(applicationProperties.getNotesRefreshTime());
refersher.addListener(new RefreshListener() {
@Override
public void refresh(Refresher source) {

                if (noteTable != null) {
                    notesTableLayout.removeComponent(notesPanel);
                    notesTableLayout.removeComponent(addNoteButton);

                    notesTableLayout.addComponent(buildNotesPanel());
                    
                    notesTableLayout.addComponent(addNoteButton);
                }
            }
        });

        MobileUI.getApp().addExtension(refersher);
    }

because the table is modfied through the container wont the Table be notified and therefore the next push will transfer the modified value?