Refreshing data from a UI component

I am trying to refresh data on a GridLayout that reads from a database after a Form from a subwindow is launched from the GridLayout and someone has filled in the form and writes it back to the database. I do not have a secondary thread doing this, its written from the Window thread by calling a utility class. I have read about Refresher (and can’t use ICEPush as this is in a portlet and ICEPush doesn’t appear to support portlets) here:


Refreshing data from a Table

I am skeptical to add a polling mechanism if I do not need it and it seems like a common requirement to me to refresh data after a form is filled out…but then I am new to vaadin and how it works so I concede for help from the experts :slight_smile: I’m hoping I am just missing something and don’t actually need Refresher.

In case it helps, the basic code of my GridLayout to open the subwindow looks like:

Button newFormButton = new Button("New Incident", new Button.ClickListener() {
            public void buttonClick(Button.ClickEvent event) {
                app.getMainWindow().addWindow(new ComplianceFormWindow(app));
            }
        });

and in that class later on is the population of the data:

      
List<ComplianceEntry> incidents = app.getComplianceService().getAllIncidents();
        BeanItemContainer<ComplianceEntry> itemContainer = null;

        if (incidents == null || incidents.size() < 1) {
            itemContainer = new BeanItemContainer<ComplianceEntry>(
                    ComplianceEntry.class);
        } else {
            itemContainer = new BeanItemContainer<ComplianceEntry>(
                    incidents);
        }

        complianceList.setContainerDataSource(itemContainer);

And the ComplianceFormWindow extends Window and has a Button.ClickListener and a Form included that does:


    Button save = new Button("Save Incident", new Button.ClickListener() {

            public void buttonClick(Button.ClickEvent event) {
                try {
                    complianceForm.commit();
                    app.getComplianceService().saveEntry(
                            ((BeanItem<ComplianceEntry>)complianceForm.getItemDataSource()).getBean());
                    close();
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
        });

Thanks for any help on this and I apologize in advance for what I suspect is a complete simple, newbie question.

No refresher or push mechanism is needed if it is the same person that is saving the form and viewing the data. The view changes will piggyback back to the browser on the browser-server roundtrip started from the save call. No additional method calls to Vaadin is needed. It’s another story when there are multiple users and all users screen should update without any user interactions when one saves new data.

What I don’t see here is how you build up the data viewing. Tables and forms would automatically update when you update the containers connected to it. You mention, however, that the data resides in a GridLayout. I will make the assumption that you just fill it with components, like Labels, and you pass data to them as strings from the real objects. These strings aren’t anymore connected to the original data object in any way as the data has probably been replaced by the form. For this reason you have to go through the separate components and re-call setValue on them with the new data.

Sorry for being vague, and might be that I answered on the wrong question, but it’s hard to be more specific without knowing what should update inside the GridLayout.

Jens thanks for the reply.

You’ve hinted me to where the issue may be. However I am still not sure how to make it work as desired. The form is bound to a bean class called ComplianceEntry. From the Form:



BeanItem complianceItem = new BeanItem(new ComplianceEntry());
setItemDataSource(complianceItem);

When the form has been filled out and they click the save button I do:


Button save = new Button("Save Incident", new Button.ClickListener() {

            public void buttonClick(Button.ClickEvent event) {
                try {
                    complianceForm.commit();                
                    getComplianceService().saveEntry(
                            ((BeanItem<ComplianceEntry>)complianceForm.getItemDataSource()).getBean()
                    );
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
        });

This is done from the Window that creates the form.

Then I have a Table that reads from the database as well to get the list of ComplianceEntry beans and displays them:


Table complianceList = new Table();
List<ComplianceEntry> incidents = getComplianceService().getAllIncidents();
BeanItemContainer<ComplianceEntry> itemContainer = new BeanItemContainer<ComplianceEntry>(
                    incidents);
complianceList.setContainerDataSource(itemContainer);

So from what I understand you are saying I somehow need to refresh the BeanItemContainer from the single BeanItem correct? Perhaps something like:


itemContainer.addBean(myFormOutputBean);

In which case I’d somehow have to pass this bean back to the Table class? Or is there a simpler way?

I’ve found a workaround by simply initiating a new Table class that re-reads the database on form submission, however I’d like to do it the “right” or Vaadin way if possible.

Thanks again for your help.

You are probably very close.

If your UI allows you to create a new Bean, then yes, after you do the commit() on the form (assuming setWriteThrough(false) is unset), the data in the form is then applied to your Bean (via the setXXX methods) – you still need to save it to the DB if you want to persist it. To have that new Bean you created in the Form appear in your Table (it doesn’t know you created a new bean), you need to add it your Container:

container.addItem(newBeanItem);

We pass the Container used by the Table to our Form when we link the two. If the Bean is selected from your Table (it already exists), you need to tell the Form to use it for display/edits via form.setItemDataSource(selectedBeanItem). In this case, when you do the form.commit(), the data will be set into the Bean and the Table will automatically be updated because it knows about that Bean.

And if your Form allows you to delete, you’ll want to do a container.removeItem(beanItem) so its no longer in the Table that uses the container.

The key is that the Container holds all of the data (BeanItems in your case – and mine!). If you create new beans, you should add it to the container. If you delete a bean, you should remove it from the container. Or you can just reload the container like you said and get a true fresh list.

The Table is used to list the contents of the Container.

The Form is used to display/edit a single BeanItem.

In our system, when a user clicks on a function, we create a View that typically is a SplitPanel that creates the Container loaded with data as desired, creates the Table and puts in the top panel and creates the Form and puts in the bottom panel.

Hope this helps…

Thanks David, this makes sense. I’ll give it a go and report back to the forum. Sounds like you guys have given me what I need.