ColumnGenerator not updating on the Container.

Hello everyone,

I’m quite new to Vaadin and I’m trying to do something quite simple. I have a container that has a boolean value. If its true I wanna change “true” to a image, if it’s “false” I wanna change to another image.

I was able to accomplish that with ColumnGenerator, however, evertime I edit one item on the container, only the boolean field isn’t updated. It only updates the boolean field if I edit the same item another time.

Here is the code:


My list

@SuppressWarnings("serial")
public class HotSiteList extends Table {

	private Admsite app;
	
	public HotSiteList(HotSitePanel hotSitePanel, Admsite app) {
		setSizeFull();
		this.app = app;
		setContainerDataSource(hotSitePanel.getHotSiteContainer());
		addGeneratedColumn("isActiveFlag", new BooleanColumnGenerator());
		addGeneratedColumn("details", new ButtonColumnGenerator(this.app));
		setVisibleColumns(HotSiteContainer.NATURAL_COL_ORDER);
		setColumnHeaders(HotSiteContainer.COL_HEADERS_PORTUGUESE);
		setColumnWidth("details", 230);
		setColumnAlignment("isActiveFlag", Table.ALIGN_CENTER);
		setColumnCollapsingAllowed(true);
		setColumnReorderingAllowed(true);
		setSelectable(true);
		setImmediate(true);
		setNullSelectionAllowed(false);

	}


My columnGenerator

public class BooleanColumnGenerator implements Table.ColumnGenerator {

    public Component generateCell(Table source, Object itemId,
                                  Object columnId) {
       	Property prop = source.getItem(itemId).getItemProperty(columnId); 
    	
        if (prop.getValue().equals(true)) {
        	Embedded img = new Embedded("", new ThemeResource("images/thumb-up.png"));
        	return img;
        } else {
        	Embedded img = new Embedded("", new ThemeResource("images/thumb-down.png"));
        	return img;
        } 
    }
}


My save button

if (source == save) {
			if (!isValid()) {
				try {
					validate();
				} catch (InvalidValueException e) {
					this.setComponentError(new UserError(e.getMessage()));
				}
				return;
			} else {
				this.setComponentError(null);
			}

			commit();

			Page hotSite = new Page();
			if (newHoteSiteMode) {
				BeanUtils.copyProperties(newHotSite, hotSite);
				try {
					this.app.getPageService().save(hotSite);
					Utils.removeSubWindow(this.app);
				} catch (Exception e) {
					this.setComponentError(new UserError(e.getMessage()));
					return;
				}
				newHotSite.setId(hotSite.getId());
				Item addedItem = app.getPagePanel().getPageContainer().addItem(newHotSite);
				setItemDataSource(addedItem);
				newHoteSiteMode = false;

			} else {
				// Seta propriedades para update
				hotSite.setId((Integer) this.getItemDataSource().getItemProperty("id").getValue());
				hotSite.setIdLayout((Integer) this.getItemDataSource().getItemProperty("idLayout").getValue());
				hotSite.setIdHotsite((Integer) this.getItemDataSource().getItemProperty("idHotsite").getValue());
				hotSite.setName(this.getItemDataSource().getItemProperty("name").getValue().toString());
				hotSite.setIdUser((Integer) this.getItemDataSource().getItemProperty("idUser").getValue());
				hotSite.setPrincipal((Boolean) this.getItemDataSource().getItemProperty("principal").getValue());
				hotSite.setGeneric((Boolean) this.getItemDataSource().getItemProperty("generic").getValue());
				try {
					this.app.getPageService().save(hotSite);
					Utils.removeSubWindow(this.app);
				} catch (Exception e) {
					this.setComponentError(new UserError(e.getMessage()));
						discard();
					return;
				}
			}

I was able to use formatPropertyValue to make it update correctly, but I would like to use the image, not just some text.
Any ideas why the container isn’t updated right away? Tkz in advance for the help.

By design, column generators are not run every time anything in the table is painted. They could perform heavy operations and do not necessarily depend directly on the container data source of the table but possibly other sources.

However, if I remember correctly, if you add the generated column with the same name as an existing property, it should “replace” the existing one and get updated when the underlying property with that name is updated.

I might be mistaken on this point - maybe Table does not listen to property changes for generated columns and/or does not trigger re-rendering of them.

Overlaying a generated column on an existing property does allow sorting on the underlying property, though.

Tkz for the fast reply. I understood what you said and it’s true. The columnGenerator doesn’t trigger the container. If I reorder my container for any of the table fields, it updates the img.

However, I have another column that I’m using ColumnGenerator (I get the id from the database and I wanna show the name, so I made the change from a list). It works perfectly fine and they are using the same idea, only one I change for a value from a list.

Here is the code for my other ColumnGenerator that changes one id for a string.

public class ValueColumnGenerator implements Table.ColumnGenerator {

	private List<Layout> listLayout;

	public ValueColumnGenerator(List<Layout> listLayout) {
		super();
		this.listLayout = listLayout;
	}

	public Component generateCell(Table source, Object itemId, Object columnId) {
		
		Property prop = source.getItem(itemId).getItemProperty(columnId);
		Layout layout = new Layout();
		layout.setId((Integer) prop.getValue());
		int index = listLayout.indexOf(layout);

		if (index != -1) {
			Label label = new Label(listLayout.get(index).getName());
			return label;
		} else {
			return null;
		}
	}

}

Any idea why it would work for one and not the other? For me, they work almost the same, only difference is that one returns a label the other a img (I tried returning a label instead of a image, but it also doesn’t work, wich means it’s not the type of what I’m returning). Tkz again for any help.