How to generate fully dynamic grid?

I use follwing code to generate dynamicly a grid and assign data out of an entity:

		final Grid<KalTabelle> myGrid = new Grid<>(KalTabelle.class, false);
		
		myGrid.addColumn(KalTabelle::getId).setKey("id").setHeader(CaptionUtils.resolveCaption(KalTabelle.class, "id"))
			.setSortable(true);

		String fieldName = null;
		for(int i = 1; i <= this.days; i++)
		{
			final int val = i;
			fieldName = "d" + String.valueOf(i);
			
			try
			{
				final PropertyDescriptor objPropertyDescriptor = new PropertyDescriptor(fieldName, KalTabelle.class);

				myGrid.addColumn(objPropertyDescriptor.getName())
				.setHeader(fieldName)
				.setSortable(true);
			}
			catch(final Exception e)
			{
				e.printStackTrace();
			}
		}
		myGrid.setSizeFull();
		myGrid.setSelectionMode(Grid.SelectionMode.SINGLE);
		this.hlLayoutGrid.add(myGrid);

		myGrid.setDataProvider(DataProvider.ofCollection(this.getAllKalTab()));
		myGrid.getDataProvider().refreshAll();

I did this because my entity(KalTabelle.class) has 366 columns (like days of a year)

but instead

				myGrid.addColumn(objPropertyDescriptor.getName())
				.setHeader(fieldName)
				.setSortable(true);
				

I would like to use a rendered column by

				myGrid.addColumn(RenderedComponent.Renderer(TextfieldComponent::new))
					.setHeader(fieldName)
					.setKey(fieldName)
					.setSortable(false);

but this did not work. The values are not assigned into the textfield.

My TextfieldComponent.class:

import com.rapidclipse.framework.server.data.renderer.RenderedComponent;
import com.rieder.pkkalender.dbmodel.KalTabelle;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;

public class TextfieldComponent extends VerticalLayout implements RenderedComponent<KalTabelle>
{
	private KalTabelle selKalTab;

	public TextfieldComponent()
	{
		super();
		this.initUI();
	}

	@Override
	public void renderComponent(final KalTabelle value)
	{
		this.selKalTab = value;
		
	}
		private void initUI()
	{
		this.textField = new TextField();
		
		this.setSpacing(false);
		this.setPadding(false);
		
		this.textField.setSizeUndefined();
		this.add(this.textField);
		this.setSizeFull();
		
		this.textField.addAttachListener(this::textField_onAttach);
	} // </generated-code>

	// <generated-code name="variables">
	private TextField textField;
	// </generated-code>
	
}

What did I wrong, or how can I use the redered component with a dynamic field assignment?

Any help is welcome

Thanks in advance

Hi,

I think in the renderer class/method, you don’t set the value (the getter).
Here I don’t see any getter:
RenderedComponent.Renderer(TextfieldComponent::new)

Something like that should be better:

final PropertyDescriptor objPropertyDescriptor = new PropertyDescriptor(fieldName, KalTabelle.class);
myGrid.addColumn(item -> new TextField(/* apply the objPropertyDescriptor to the item - like item.getValueForFieldName()*/)))
					.setHeader(fieldName)
					.setKey(fieldName)
					.setSortable(false);

You will probably get multiple problems with this approach:

  • A component renderer is quite slow in the grid and there is no virtual horizontal scrolling in the grid. So you will have 366 component columns which will be rendered slowly.
  • It’s not easy to set the value from a component renderer in a grid.

I don’t know exactly your need but I think the grid is not the best fit for it.
Perhaps this component is better: https://vaadin.com/directory/component/infinitegrid/samples

Thank you Jean-Christophe!

In my first try,
i generate the grid columns by

			myGrid.addColumn(objPropertyDescriptor.getName())
				.setHeader(fieldName)
				.setSortable(true);

i use setDataprovider to assign the data:

		.....
		myGrid.setDataProvider(DataProvider.ofCollection(this.getAllKalTab()));
		myGrid.getDataProvider().refreshAll();
		.....

With this the data get loaded into the grid.
My second try was to change the generation to a rendered component, to get control over the rendered component.
But with usage of the rendered component, the dataprovider did not assign the values into the component.
My basic reason is, because later on, I would like to colorize the renderd component based on the content.
Perhaps if there is a value “SA” for saturday or “SU” for sunday the cell background, or as I thought the rendered component should be colored.

But you are right. With rendered component it is slower like my first try.

I will try to test the infinitegrid, like you suggested.