Table in master-detail

Hello,

If detailed data is displayed in a table, does anyone know how to refresh all contents in the table when master is changed?

Thanks,
Watt

Don’t really understand what you mean with detailed data and master, but if you just mean changing the content of the container attached to the table, then nothing. Changing properties of the container is automatically passed all the way to the browser, with the exception of the special use case when you update the data in a separate thread.

I understand the question as follows:

In order for that to happen, you must react to the change in the property value in the table. The cell in your table must have a handler that reacts to value changes in that cell. In the handler that deals with the change, you must recompute the total, and make sure that the property that displays it is changed by calling its setValue(). If you manipulate the properties, everything is automatic and you have nothing else to do.

The key is that setting the property through the interface will manipulate the underlying data – this is called binding. For example. if you are using a BeanItemContainer, the item properties are actually linked to java object fields, and setting a user interface property changes the underlying field in the java object.

If you change the total in the underlying Java object, Vaadin doesn’t know that it needs to repaint. Then you have to request the repaint yourself.

Thanks and sorry for the unclear description.

The real scenario is that there is an 1:n relationships (master:detail) between two tables, I could use ComboBox to display master, and Table for details. When the value in Combobox is changed, values in Table should follow the change. I try to replace BeanItemContainer of Table with another, then repaint the table. The content in the table doesn’t refresh.

Should I “change the content of the container” one by one?

I had the same problem and had to do a refresh function, I hope that will be useful.


/**
	 * Refresh table data from a QueryContainer. The previous content of table
	 * is removed and new data is loaded from the provided QueryContainer.
	 * 
	 * The value of the first property of QueryContainer will be used as
	 * Item ID in table.
	 * 
	 * @param qc 			A QueryContainer with data to load
	 * @param table			Table to refresh
	 * @param properties	Array of properties IDs to use
	 */
	public void refreshTable(QueryContainer qc, Table table) {
		table.removeAllItems();
		
		int qcsize = qc.size();
		if (qcsize == 0) {
			Logger.log("DatabaseStorage.refreshTable() empty query container");
			return;
		}
		
		List<Object> propertyIds = new ArrayList<Object>(qc.getContainerPropertyIds());
		int propertiesnumber = propertyIds.size();
		if (propertiesnumber <= 1) {
			Logger.log("DatabaseStorage.refreshTable() query container needs more than one property");
			return;
		}
		
		for(int i=1; i<=qcsize; i++) {
			Item dataItem = qc.getItem(i);
			Item tableItem = table.addItem(dataItem.getItemProperty(propertyIds.get(0)).getValue());
			if (tableItem == null) {
				Logger.log("DatabaseStorage.refreshTable() couldn't add new table's item");
			}
			for(int j=1; j<propertiesnumber; j++) {
				Object pid = propertyIds.get(j);
				//System.out.println("DatabaseStorage.refreshTable() pid: " + pid);
				tableItem.getItemProperty(pid).setValue(dataItem.getItemProperty(pid).getValue());
			}
		}

	}



Hmm… As far as I know, changing the container of the table should be the only thing you have to do to. Could you provide a test case of your problem?

I created a simple test case, it worked:

        cbx.addListener(new ComboBox.ValueChangeListener() {

			@Override
			public void valueChange(ValueChangeEvent event) {
				Continent continent = (Continent) event.getProperty().getValue(); 	
				String name = continent.getName();
				
				BeanItemContainer<Country> container = null;
				if ("Africa".equals(name)) {
					container = getCountryContainer(AFRICA);
				} else
				if ("Asia".equals(name)) {
					container = getCountryContainer(ASIA);
				} else
				if ("Europe".equals(name)) {
					container = getCountryContainer(EUROPE);
				}
				
				if (container != null) {
					table.setContainerDataSource(container);
					table.requestRepaint();
				}
			}
        	
        });

I would check my code again to see whether it is caused by the complexity of UI or not.

Thank you.

[Edit]
Finally it worked fine. Before table.requestRepaint(), visible columns and column headers should be set again (no idea why):

		        table.setVisibleColumns(...);
		        table.setColumnHeaders(...);	

Hmm. Good that you get it to work but the funny part is that you shouldn’t have to call requestRepaint() at any point, and neither should you have to reset the headers.

I think setImmediate() method of the table should be set to “true” in order to change in datasource be immediately sent to server and repainted. Have to still try this though to verify.