Table data updates

Hi people,

I have a Table that is populated with an HbnContainer, and this works fine so far. I also have Form, that is used to change the rows in the Table.

When the Table selection is changed, the Form method setItemDataSource gets called with the row from the Table.

But when I change something in the Form and call commit(), the table isn’t updated. The database entry is updated, so if I reload the full app the changed entries do appear.

What is the best way to make the table update when a Form changes one of the entries in the HbnContainer?

Bo Thorsen,
Monty Program AB.

Hi Bo,

Did you get to solve your problem? I have a similar problem. When I delete data in the DB, I can still see it in the table. I only see new changes when I restart the application or invalidate the session. Is there a better way to load data in the table so that one has real-time display of what in in the database. As in …is there a way to refresh the table once the changes to the underlaying data store is made without having to restart the application or expire the session. I have even tried setting the table to null first before loading it with data and it seems not to work.

Good day

B Kabs

Hey guys,

The Table component always updates when the container fires an ItemSetChangeEvent, so if this isn’t happening you need to find a way to trigger it.

In Bo’s case, it looks like a possible solution would be to add a call to the fireItemSetChange() method in the HbnContainer.EntityItem.EntityItemProperty.fireValueChange() method. After this change, the Table will always refresh when any entity is changed in some way. This of course requires the Form (or whatever is used) to use
the same EntityItem instance
as the data source.

By default the Table has an IndexedContainer. In this case there’s no straightforward way to trigger the ItemSetChangeEvent. Either you need to create a container of your own, or do an removeItem(oldEntity) addItem(storedEntity).

HTH,
/Jonatan

Hi Jonathan,

Thanks for your response. Am just not sure how to do what you said. Here is my code

For the container


public class PersonContainer extends IndexedContainer {

    public static final Object COLUMN_ORDER = new Object[]{"surname", "firstname"};
    public static final String[] COLUMN_HEADERS = new String[]
{"Surname", "First Name"};
    public static final String PROPERTY_SURNAME = "Surname";
    public static final String PROPERTY_FIRSTNAME = "First Name";

    public PersonContainer() {
    }

    public PersonContainer(List<ReportPerson> list) {
        addContainerProperty(PROPERTY_SURNAME, String.class, null);
        addContainerProperty(PROPERTY_FIRSTNAME, String.class, null);
        


        for (ReportPerson reportPerson : list) {
            Item item = addItem(reportPerson.getId());
            item.getItemProperty(PROPERTY_SURNAME).setValue(reportPerson.getSurname());
            item.getItemProperty(PROPERTY_FIRSTNAME).setValue(reportPerson.getFirstname());
        }
    }
}

And for the Table



public class PersonnelList extends Table {

    private ReportPersonServices reportPersonServices;

    public PersonnelList(TimsApplication app) {

        SpringContextHelper helper = new SpringContextHelper(app);
        reportPersonServices = (ReportPersonServices) helper.getBean("reportPersonServices");
        List<ReportPerson> list = reportPersonServices.getAllReportPerson();
        
        PersonContainer t = new PersonContainer(list);
        setSelectable(true);
        setImmediate(true);
        addListener((Property.ValueChangeListener) app);
        setNullSelectionAllowed(false);
        setSizeFull();
        
        this.removeAllItems();
        setContainerDataSource(t);
    }
}

Am getting a list of reportPerson Objects from a Spring middle tier with a JPA back end. The only way I could call the something close to what you suggested-removeItems on the table was calling the line 20 in the above code, but still that does not work. When I just do a batch delete of all records from the DB, they don’t vanish but still show in the table even after a browser refresh. Isn’t there a way to easily reload the table when the page renders or at least provide a refresh button that will reload the table?

Hi,

So what you are doing here is basically:

  • fetch data from somewhere
  • copy it to an IndexedContainer
  • associate the container with a table

After this no matter how many times you reload the application the content will not change as the content of the data source (indexed container) does not change. If you delete your whole DB the content of the indexed container still does not change.

What you need to understand is that the state of the application lives on the server side so refreshing the browser will not create a new application (and a new Table etc).

So, to make the content change you need to alter the container contents (remove items) or create a new container and set that as the data source for the table. If you have a refresh button you should assign a click listener to it and update the container in the listener.

Btw. there is a BeanItemContainer that you can use instead of extending IndexedContainer. You can directly add a list of data objects to the BeanItemContainer

Mr Anonymous got it right. Vaadin applications are stateful and retain their state over the entire session.

This means that if you’re using a normal IndexedContainer, you need to update the state of it manually, since it doesn’t know anything about the data store. Using the code you pasted you basically have to create a new container each time an item in the ReportPerson list is changed or added to / removed from the list. E.g.


public class PersonnelList extends Table {

    public update() {
        // Get an updated list from the data store
        List<ReportPerson> list = reportPersonServices.getAllReportPerson();
        
        // Create a new (updated) container with the new list
        PersonContainer t = new PersonContainer(list);
        
        this.removeAllItems();  // just to be sure
        setContainerDataSource(t);
    }
    
}

And then you need to make sure that the PersonnelList.update() method is called each time the data returned by getAllReportPerson changes.

Using the BeanItemContainer or creating a container of your own, specifically bound to your data store (check out
the HbnContainer example
) you don’t need to do these things manually any longer.

Hope this didn’t confuse things even more :slight_smile:
/Jonatan

Hi folks,

I have managed to work round my issue. I think realising that the Vaadin applications are stateful was key. I basically followed Mr Anonymous’s advise. What I did was call a fresh view once the delete method was executed. I also had to change my views to not load them lazily. Basically from this

  
public PersonnelListView getPersonnelListView(){
if (personnelListView == null) {
        personnelList = new PersonnelList(this);
        competencyList = new CompetencyList(this);
        personnelListView  = new PersonsListView(personnelList, competencyList);
     }
 return personnelListView;
}

to this


public PersonnelListView getPersonnelListView(){
        personnelList = new PersonnelList(this);
        competencyList = new CompetencyList(this);
        personnelListView  = new PersonsListView(personnelList, competencyList);
       return personnelListView;

So I get my views freshly created from the data source. I don’t know if this is the best way, but will give Jonatan 's idea a shot if I run into issues with my method.( Got the name spelling correct this time :smiley: )

On the
BeanItemContainer
, I think last time I tried it, it had “too much magic embedded in it”. Its a great class and works wonders, but I didn’t know how to control what fields to display in the table. It displayed everything. I feel I have much control with
IndexedContainer

Am just not too sure about
HbnContainer
. Perhaps I have not given it too much thought. From a bird view angle, it strikes me like, I will have to reconfigure my data source to use Hibernate. I have a middle-tier and a hibernate JPA back end which works well with other front ends. I feel if I use
HbnContainer
, I have to redo those tiers. Is that a correct assumption, Jonatan? Will perhaps try it on a future green field project.

Again thanks for your help and input

Kabs

So the BeanItemContainer creates properties for all the fields (that has getters) in the data class, i.e. the property “name” contains the object returned by the data class’ getName(). You can create what is displayed in e.g. a Table using table.setVisibleColumns(new Object {“name”,“age”}) and if you want different headers for the properties you can use table.setColumnHeaders(new String
{“Username”,“Age”}).

You are correct. To use the HbnContainer you need to use Hibernate to access your data. Compared to using SQL Selects however I would say it pays off to do the Hibernate configuration and directly get objects as results from queries even if you are not using HbnContainer. (You can use the objects with a BeanItemContainer also if you feel like it).

Where can I find the latest version of HbnContainer? Maybe the one I have isn’t the latest version because there is no fireValueChange anywhere.

Bo.

I tried calling fireItemSetChange() from EntityItem.setValue(), and that didn’t help. When adding a new entry to the database, it doesn’t update as it’s supposed to.

Bo.

I figured out what the problem was now. I wasn’t using the HbnContainer and HibernateUtil classes correctly - I added and deleted objects directly with the HibernateUtil class. Now I changed to use the HbnContainer methods, and it started to work properly.