Display problem of TreeTable and performance is not good

We use TreeTable component in our product. But when we try to display the treetable content, we got a problem.

For example, we have 3 top level tree node and the first node has 3 children. When trying to expand the first node, the 3 children is displayed at the bottom of the table. Not under the first node. But when you collapse the first node and expand again, then no problem. Please check the attched screenshot:outOfServiceErro.JPG

The following is our implementation. We do not want to expand all nodes at the begining for it will impact the performance, we implement the expandListener. That means we only expand the node when user click it.

Meanwhile, the performance is no good when we expand the node. It will take 3-5 seconds to expand one node even though it only has 2 sub-items.

reasonCodeContainer is the Container, reasonCodeHierarchical is ContainerHierarchicalWrapper.


treeTable.addExpandListener(new Tree.ExpandListener()
{
	@Override
	public void nodeExpand(ExpandEvent event)
	{
		Object openedItemId = event.getItemId();
               
        List<ReasonCode> list = findChildren((ReasonCode)openedItemId);
        buildContainer((ReasonCode)openedItemId, list);
	}
});

private void buildContainer(ReasonCode parent, List<ReasonCode> children)
{
	for (ReasonCode reasonCode : children)
	{
		reasonCodeHierarchical.setParent(reasonCode, parent);
		treeTable.setCollapsed(parent, false);
	}	
}

private List<ReasonCode> findChildren(ReasonCode reasonCode)
{
	List<ReasonCode> result = new ArrayList<ReasonCode>();
		
	List<ReasonCode> existedReasonCode = reasonDTO.getReasonCodes();
	if(!existedReasonCode.isEmpty())
	{
		for (ReasonCode existCode : existedReasonCode)
		{
			if(existCode.getParentObject() != null && existCode.getParentObject().equals(reasonCode))
			{
				reasonCodeContainer.addItem(existCode);
				result.add(existCode);
			}
		}		
	}	
	return result;
}

edit: added code markdown
13117.png

I might be totally wrong here, but the way you have implemented your ‘optimization’ is really weird. For each expand, you get ALL items from the backend, and then filter them in UI code? Why don’t you just add them all at once and be done with it?

This leads to an important optimization rule for Vaadin containers; do not add items after you have added the container to a select. Each add-call will repaint the complete component! If you need to add items, detach the container first, add the items, and re-set the container.

Just try adding all items at once, I bet it will be a lot faster.

Excuse a stupid question, but how do I detach a container from a component? There is no method
AbstractSelect.removeContainerDataSource()
or similar? And using
setContainerDataSource(null)
gives me an exception.

setContainerDatasource(null) is what you want; can you provide the stacktrace, please?

com.vaadin.event.ListenerMethod$MethodException: Invocation of method nodeExpand in info.thebloodbank.common.NodeTable$1 failed.
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:528)
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:167)
at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:992)
at com.vaadin.ui.TreeTable.fireExpandEvent(TreeTable.java:798)
at com.vaadin.ui.TreeTable.toggleChildVisibility(TreeTable.java:563)
at com.vaadin.ui.TreeTable.changeVariables(TreeTable.java:421)
at com.vaadin.server.communication.ServerRpcHandler.changeVariables(ServerRpcHandler.java:403)
at com.vaadin.server.communication.ServerRpcHandler.handleBurst(ServerRpcHandler.java:228)
at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:111)
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:111)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:37)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1314)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:195)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:964)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:304)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.NullPointerException: Null can not be wrapped
at com.vaadin.data.util.ContainerHierarchicalWrapper.(ContainerHierarchicalWrapper.java:116)
at com.vaadin.ui.TreeTable.setContainerDataSource(TreeTable.java:594)
at info.thebloodbank.common.NodeTable$1.nodeExpand(NodeTable.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:508)

OK, that is clearly a bug… you can do a workaround by calling setContainerDataSource(new HierarchicalContainer()) instead. I created a ticket about it:
http://dev.vaadin.com/ticket/12928