Table not updating after item property value change

I’m doing something simple and it’s not working. This is with Vaadin 6.7.6.

  1. I create a
    Table
  2. I create an
    IndexedContainer
    and add four container properties via
    addContainerProperty(Object, Class<?>, Object)
  3. I call
    table.setContainerDataSource(container);

Later, when I want to add a new row, I do this:

  1. I add a new
    Item
    via
    item = container.getItem(container.addItem());
  2. I then set property values via
    item.getItemProperty(…).setValue(…)

The problem is that when I add a new row, the new row appears, but all the columns have their empty default values. It’s as if step #2 didn’t happen.

But then if I then add another row, the same thing happens on the second row, but also the columns/values in the first row then suddenly appear.

In other words, it is as if the table is getting a notificatiions from the new item change in step #1 but not from the item property change in step #2, and only after a subsequent notification from the next step #1 does the change in the previous step #2 get propagated to the Table.

I’m confused. I thought Tables and Containers were set up so that property value changes were automatically propagated.

What am I doing wrong here?

Thanks.

If the property change to your table is being done as a result of a user action (that is, in a listener, or a routine invoked from a listener), then you should see it – vaadin should repaint.

If the property change is done some other way, and not as a result of a user action, then you need something like ICEpush, or DontPush Ozone, to ensure that the browser is informed of the change.

The behaviour you describe is consistent with the second scenario: your change to the interface is queued, and until the browser comes back to query the web server, nothing happens. The queued changes are all sent on the next interaction.

No, I don’t think that the behavior described is consistent with the common “browser just needs an update” situation.

The browser
does
in fact update - it clearly shows the new row. The problem is that the row’s values are all empty.

Note that my creating the new item (step 1) and setting the values (step 2) happen right together in the same Java method and thread of execution, so if Vaadin is only delivering the results of the first action to the browser then there is a bug.

Vaadin seems to have a bug where after the second action (step 2), it thinks that it has already queued the necessary update, but what it has queued is really only the update for step 1.

Not sure if setValue method on individual property is firing a value change so that table is informed about the changes immediately. If you are getting the updated table after step 1 means that at that stage it is firing a value change event.

I my opinion, firing a value change on every individual property may be expensive.

Writing web based applications are trickier than normal desktop applications. Sometimes, you may even want to postpone a table update towards the end when populating large number of rows. So, container may be filled up even before the table is actually constructed.

Thanks, but performance considerations are not relevant to this discussion. I’m talking about a functional bug.

I think I figured out what is going on.

The problem is that the columns that are not updating are generated columns: they are being generated based on Item properties, rather than having the Item properties displayed directly.

Apparently the Table implementation assumes that generated properties can’t change even though the Item that they are based on has changed. This seems like it a wrong assumption 99% of the time… after all, what else would you be generating them from?

Here’s a Vaadin application that demonstrates the problem (Vaadin 7):

import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.Root;
import com.vaadin.ui.Table;
import com.vaadin.ui.VerticalLayout;

import java.util.Date;
import java.text.SimpleDateFormat;

@SuppressWarnings("serial")
public class VaadinBugRoot extends Root implements Button.ClickListener {

    private final IndexedContainer container = new IndexedContainer();

    public VaadinBugRoot() {
        super("Vaadin Bug Test Case");
    }

    @Override
    public void init(WrappedRequest request) {

        final Table table = new Table("test table");
        table.setWidth(600, Sizeable.Unit.PIXELS);

        this.container.addContainerProperty("time", Date.class, null);
        this.container.addContainerProperty("value", String.class, "");
        table.setContainerDataSource(this.container);

        table.addGeneratedColumn("time", new Table.ColumnGenerator() {
            @SuppressWarnings("unchecked")
            public Object generateCell(Table table, Object itemId, Object columnId) {
                Property<Date> timeProperty = (Property<Date>)table.getItem(itemId).getItemProperty("time");
                Date date = timeProperty.getValue();
                if (date == null)
                    return "(none)";
                return new SimpleDateFormat("HH:mm:ss").format(date);
            }
        });
        table.addGeneratedColumn("value", new Table.ColumnGenerator() {
            @SuppressWarnings("unchecked")
            public Object generateCell(Table table, Object itemId, Object columnId) {
                Property<String> valueProperty = (Property<String>)table.getItem(itemId).getItemProperty("value");
                return "Value is \"" + valueProperty.getValue() + "\"";
            }
        });

        Button button = new Button("Add Row", this);

        VerticalLayout layout = new VerticalLayout();
        layout.setSpacing(true);
        layout.setMargin(true);
        layout.addComponent(table);
        layout.addComponent(button);

        this.setContent(layout);
    }

    @Override
    @SuppressWarnings("unchecked")
    public void buttonClick(Button.ClickEvent event) {
        Item item = this.container.getItem(this.container.addItem());

        Property<Date> timeProperty = (Property<Date>)item.getItemProperty("time");
        timeProperty.setValue(new Date());

        Property<String> valueProperty = (Property<String>)item.getItemProperty("value");
        valueProperty.setValue("Foobar 123");
    }
}

FWIW, I filed
bug #8771
.

This is a long known limitation - see e.g.
this forum thread
and
documentation ticket #3158
. However, it might be doable to just mark the cache as invalid (at the moment for the visible buffer, in the future perhaps only for the row or the cells) when updating cells on a row that does have generated columns, but even in this case only for visible column updates as the Table only listens to their changes.

Sometimes generated columns also use data from other rows or other data sources. In these cases, a generic automatic update mechanism is not possible.

Ugh. Then it seems like the whole “generated column” concept is fundamentally broken.

I’d suggest “fixing” this by deprecating “generated columns” and providing some tools for solving this kind of thing another way.

For example, Vaadin could supply some
Item
“wrapper” superclasses that make it easy to add “generated properties” to an existing
Item
. Then you could build your Container using the wrapper Items, etc.

I’m going to agree with Archie here.

I’ve long felt the table handling in Vaadin is convoluted and needlessly complex. I understand it is trying to cater to a wide range of scenarios.

But something as basic as “update the table because the underlying data changed” is such a common aspect of interactive web applications to take the view that such a “long standing problem” is acceptable is a shame given the incredible quality of the rest of Vaadin.

I used to develop in ZK (for close to 3 years) and found it excellent by and large, however, the volume of code needed to create web apps was higher than Vaadin, despite, in my opinion, ZK method of XML UI generation being more maintainable (a view shared by the creators of Clara, VulComposer. etc. addons).

Despite a number of drawbacks in Vaadin (notably less UI widgets than ZK in real terms) I still find Vaadin more productive, hence I develop in it by choice.

However, interestingly, I had to use ZK 6.5 recently and especially the new Data Binding framework and it is MUCH improved. However, Vaadin in my opinion, is still more productive. But the gap has narrowed significantly.

In all this, I have not used Vaadin 7 since most of the addons I use do not support it yet. So perhaps my issues with tables are fixed there.

But I would add a VERY strong plea to the Vaadin team to review these issues around usage of tables, it is in my view, the only really large glaring weakness in an otherwise excellent product.


PS I am not intending to start a flame war of ZK vs Vaadin, they are both mature, capable tools in my view, each with its strengths and weaknesses. As noted, even though I think ZK is more developed in many areas, I still prefer Vaadin.

Push support is currently planned for Vaadin 7.1 (addressing a part of this), and there are some improvements to the data model (and especially forms etc.) in Vaadin 7.0.

A rewrite of the table component is high on our list of priorities, but unfortunately did not happen yet. More on that in future roadmaps.
The fundamental data model is not likely to change much anymore before Vaadin 8, but I do believe the new table will be significantly more flexible than the current one.

Hi Henri,
Thanks for the prompt reply. I’m glad to hear the table is up for an “upgrade”. However, I agree with Archie, this is less of a server “push issue” it is more a case that:

  1. User does some interaction, e.g. edit an entry in a bound object
  2. Which affects underlying bound table data
  3. Expected Result: Table updates, Actual: Nothing

I would agree with you 100% if a background thread for example, changed information. But in my use case and Archie’s I believe, the user did some action that affected directly the bound data.

I can prove the assertion, by simply using the same code style as the Tutorial where the Address Book is edited in a form. I’ve recreated the code exactly in my application. The Form object correctly updates the underlying Java Bean.

If you put a System.out.println (…) comment the correct bean values are shown after the form edit finishes.

BUT the stubbornly remains unaffected.

The very kludgy workaround of:

table.setDataSource ( table.getDataSource() ) ;

Does work, but it is messy, may have large performance implications and is just plain unnecessary code. One of the things I really like about Vaadin is precisely that for the most part, there is little unnecessary code.

Thanks for listening to my rant :grin:
Anthony

Was / is there any progress on this table-refresh issue?
(please no “move to grid” answers or similar). Thx.

Hi everyone,

I am trying to migrate my application from vaadin7 to 8. But I am not able to find any package for Table.
Could you please tell how can I use method Table.ColumnGenerator() in vaadin 8???

Thanks,
Mahesh

dear Mahesh,

i just spend the last Months migrating our Application from 7 to 8, so initialy i was not sure how to answer this :slight_smile:

The Table is no more, you have to rebuild it in Grid.

I hope this will help you :slight_smile:

[https://vaadin.com/blog/mission-rip-table-migrate-to-grid-data-and-structure]
(https://vaadin.com/blog/mission-rip-table-migrate-to-grid-data-and-structure)

That’s not exactly true, the Table still exists in the [Compatibility package]
(https://vaadin.com/docs/v8/framework/migration/migrating-to-vaadin8.html). But it is deprecated and you will probably benefit from migrating to Grid sooner or later.