LSPS documentation logo
LSPS Documentation
Grid (forms::Grid)

The Grid component displays single-line text data in a tabular layout and enables editing of persistent data and row selection.

The data is lazy-loaded, which prevents potential performance issues when the grid is loaded.

Grid cells cannot hold further components. However, you can modify how the column content is rendered and render it, for example, as a button or a link, using renderers.

Designing a Grid

To create a Grid with your content, do the following:

  1. Insert the Grid component into your Form.
  2. Define the data-source type and the expression that returns it.
    datasourcegrid.png
  3. Insert the Grid Column components and define their properties ( ) into the Grid. You can insert grid columns dynamically with the addColumn() method.

Creating a Grid Column

To create a column in your Grid, do the following:

  1. Insert the Grid Column component ( ) into the Grid.
  2. Select the type of the value provider, which return the column item:
    • Property path: path to the property of the record used as the Grid's data source, for example, Person.id
    • Closure: closure that returns the column item with the grid data object as its input argument, for example, { s:SavedDocument -> toString(s.id)}

      Note that the renderer of the column (defined below) has the input argument of the closure as its input.

    • Identity: unchanged row object
    • Custom: custom implementation of forms::ValueProvider
  3. Define the renderer (determines how the value from the value provider is rendered):
    • None renders the value as returned by the toString() call.
    • HTML renders a String value as HTML.
    • Number renders the value in the format defined below.

      Define the format as a String following the DecimalFormat Java formatting rules, for example, "0000.00000"

    • Date renders the value in the format defined below.

      Define the format as a String following the SimpleDateFormat Java formatting rules in the text area below, for example, "EEE, d MMM yyyy HH:mm:ss" results in formatting Wed, 7 Sep 2016 14:33:00

    • LocalDate: renders the Value Provider value in the defined format

      Define the format as a String following the SimpleDateFormat Java formatting rules in the text area below, for example, "EEE, d MMM yyyy" will result in formatting like Wed, 7 Sep 2016

    • Enumeration renders an Enumeration value as a String.
    • Button renders the value as a Button.

      The click action is defined as a closure with the value-provider object as its input parameter below.

      { clickRowObject:String ->
          varString := "The user clicked: " + clickRowObject.toString();
          MyEditableGrid.refresh()}
    • Link renders the value provided by the Value Provider as a Link

      The click action of the link is defined as a closure in the field below. The input of the closure depends on the type of the value provider; for Property path, Constant, and Identity, the input is the return value of the closure; for Closure, the input is the row object:

      {  clickRowObject:String ->
          varString := "The user clicked: " + clickRowObject.toString();
          MyEditableGrid.refresh()}
    • Theme image considers the value to be the path to a Vaadin ThemeResource image and renders the image. The value provider must return a String with the path to the image. The path is relative to current Vaadin theme directory, for example, myapp-war/VAADIN/themes/lsps-blue", so the String path could be "favicon.png". The on-click action is defined as a closure with the Value Provider object as its input parameter below.
    • External image considers the value to be the URL to an image and renders the image. The Value Provider must return a String with the URL to the image. For example, external image renderer could be used if for a Closure Value Provider set to {a:Applicant -> "www.acme.com/images/" + a.pictureName}.
    • Component considers the value to be a form component.

      Important: The component with its subtree components is generated for each column cell. In the case the component tree is complex, this can result in performance issues; Therefore, using the Component renderer is discouraged and other renderers should be used preferably whenever possible. It is provided primarily to allow full migration of Tables to Grids.

    • Custom uses a custom renderer that implements the forms::Renderer interface (For further instructions, refer to the developer documentation.
gridColumnRenderer.png
Theme image renderer

Creating a Grid Column Dynamically

To add a column dynamically on runtime, for example, when the user clicks a button, call the addColumn() method on the parent component.

{e -> Vocab.addColumn(
    new forms::TableColumn(
        data -> null,
        modelingId -> null,
        filtrable -> false,
        generator -> null,
        sortable -> false,
        valueProvider -> new PropertyPathValueProvider(Unit.svk))
    )
}

Hiding a Grid Column

You can hide columns of tabular components can be collapsed from the front-end by the user as well as programatically. You can also enable or disable the feature.

By default, Columns can be displayed:

  • To disable hiding of a Column, call the setHiddable(false) method on the Column.
  • To hide and show a Grid Column, call the setHidden() method on the Column.

Ordering Grid Columns

To change the order of grid columns, call the setColumnOrder() method on the grid column ordered as required.

//restoring column order from an listener:
{ _ ->
  def List<GridColumn> allColumns := myGrid.getColumns();
  myGrid.setColumnOrder(
       allColumns.sort({
       a:GridColumn, b:GridColumn ->
         switch a.getHeader() > b.getHeader()
           case true -> 1
           case false -> -1
           default -> -1
         end
       })
  );
}

Enabling Drag-and-Drop of Grid Columns

To allow drag-and-drop of grid columns, use the setColumnReorderingAllowed(true) call.

Sorting a Grid

Sorting is defined per Grid Column. To enable it, do the following:

  1. Open the column properties and select the Detail tab.
  2. Select the sortable flag.

Alternatively, you can sort based on a grid column with the setSorted() method. The method ignores the setting of the Sortable option of grid columns.

//sorting myColumn in descending order:
myColumn.setSorted(true, false);

You can check the status of the column sorting with the isSorted() and isSortAscending() call.

Important: When applying sorting on large collections (the Data Source is set to Collection), sorting actions might cause performance issues: consider using other data sources such as shared Type data sources.

GridColumnRendered.png
Filterable and sortable Grid Column

Filtering a Grid

Important: Filters on Columns of Grids support only the Boolean, String, Integer, Decimal, Date, and Enumeration data types.

To enable filtering on a Grid column, do the following:

  1. Make sure the Grid is filterable: the flag is set with the setFilterable(true) method and is enabled by default.
  2. On the respective column, set the filtering properties:
    1. On the Detail tab, select the Filterable flag.
    2. Optionally specify the filter properties with the setFilterConfig() method.
      • OptionsFilterConfig: the user will be able to select one or multiple OptionsFilterConfig from an option set, which will be interpreted as the values and applied by the filter.
        def SelectItem adv :=  new SelectItem(label -> "Advanced", value -> Level.ADVANCED);
        def SelectItem int :=  new SelectItem(label -> "Intermediate", value -> Level.INTERMEDIATE);
        def SelectItem beg :=  new SelectItem(label -> "Beginner", value -> Level.BEGINNER);
         
        c.setFilterConfig(
           new OptionsFilterConfig(
              multiselect -> true,
              options -> [
                  adv, int, beg
              ],
              selected -> [adv, int]
              )
        )
      • NumericFilterConfig: the user will define a number range
        // numeric filter with default values:
        new NumericFilterConfig(equal ->50, moreThan -> 10, lessThan -> 90)
      • DateFilterConfig so the user can define a date range to use for filtering and the format of selected dates
        new DateFilterConfig(
          resolution -> uicommon::DateTimeResolution.Month, formatPattern -> "YYYY MMMM"
        )
      • RexExpFilterConfig to define the default regex pattern for filtering
      • SubStringFilterConfig to define the default substring pattern for filtering
      • BooleanFilterConfig to define properties of filter for Boolean values

Also if you are designing a filterable grid with a custom data source, the filter properties (its id) will allow you to identify the filters with set values using the filter id.

filterConfig_grid.png

Important: When applying filtering on large Collections (the Data Source is set to Collection), sorting and filtering actions might cause performance issues: consider using other data sources such as shared Type data sources.

GridColumnRendered.png
Filterable and sortable Grid Column

Working with a Component in a Grid Row

If you need to perform an action on a cell with a component in a grid row, use the getComponentInRow() method: the method returns the component in the cell of the grid column.


//Closure value provider expression of a grid column
//which refreshes the value of the row object in another Columns
//whenever it is changed (renderer is set to Component):
{ mr:MyRecord ->
   def TextField tf := new TextField("caption", &mr.field);
   tf.setOnChangeListener({ e ->  myc.getComponentInRow(mr).refresh();myc3.getComponentInRow(mr).refresh();});
   tf
}

{ e ->
  def Object rowObject := myg.getDataSource().getData(0, 1, null, null)[0];
  check.setValue(myGridColumn.getComponentInRow(rowObject))
}

Editing a Grid

Important: When enabling editing of Grid data, make sure to consider the following:

  • Since Collections are immutable, you can enable editing only on a Grid with shared Records and Grid Columns with the Value Provider set to Property path.
  • If the underlying associated shared Record Property returns null, the cell will remain empty and read-only.

To enable editing of shared Record Properties in a Grid, do the following:

  1. Open the Properties view of the Grid component:
    1. Select the Editor enabled flag.
    2. To save the changes only when the user clicks the Save button in the edited row, select the Editor buffered flag. If the Editor buffered is not selected, the changes are applied to the underlying Record instantly (on every change).
  2. Enable editing on the Grid Column:
    1. Open the properties of your Grid Column.
    2. Select the Editable flag.
    3. In the Editor field, define which editor should be used on the Value Provider object:
      • leave empty for Strings
      • NumberEditor: the user will be able only to provide a number (Decimal or Integer)
      • DateEditor: the user will be able to insert only a date with the option to use a date picker
      • EnumerationEditor: the user will be able to select one of the Enumeration value from a drop-down box
        GridEditableColumn.png
        Editable Column with a date value

Enabling Row Selection in a Grid

To allow the user to select grid row and perform an action on row selection, do the following:

  1. Make the Grid selectable using the setSelectable(true) call.
  2. Set the selection mode with the setSelectionMode(SelectionMode) call:
    • SelectionMode.NONE: selection disabled
    • SelectionMode.SINGLE: single-row selection on click
    • SelectionMode.MULTI: selection of multiple items using checkboxes in individual rows

      In the MULTI mode, the user can select multiple rows directly under each other by clicking the selection checkbox of the first row, holding the click, and dragging the mouse across the rows below.

  3. To handle a selection, call the setSelectionChangeListener() method on the Grid component: its closure parameter defines how to handle the selection.
  4. To select a Grid row, call the select() method.
//on the Init tab of Properties view:
//enable selection:
c.setSelectable(true);
//set selection mode:
c.setSelectionMode(SelectionMode.MULTI);
//select rows with first two items from the datasource:
c.select(c.getDataSource().getData(0, 2, null, null));
 
//you can also select a particular item in a Collection
//datasource (in SINGLE selection mode):
//c.select(mycollection[0]);
 
//display selected items in an output component:
c.setSelectionChangeListener(
  {
    v:forms::ValueChangeEvent ->
      //set the content of an output component to the selected row:
      labelComponent.setValue(
        c.getSelection().toString());
  }
);

Enabling Selection of All Rows

To enable the Select All option on a Grid, set the Grid as selectable in MULTI selection mode and display the Select All checkbox:

c.setSelectable(true);
c.setSelectionMode(SelectionMode.MULTI);
c.setSelectAllCheckBoxVisible(true);

Enabling Selection of Multiple Rows in a Grid

To enable the Select All option on a Grid, set the Grid as selectable in MULTI selection mode and display the Select All checkbox:

c.setSelectable(true);
c.setSelectionMode(SelectionMode.MULTI);
c.setSelectAllCheckBoxVisible(true);

Displaying Detail Row in the Grid

To display a row with data in a Grid when the user clicks a row, do the following:

  1. Create the detail form, which will be displayed in the detail row:
    1. Create a form definition.
    2. Create a variable that will hold the object with the detail data, for example, create a form variable of type Person.
    3. Create a constructor that will have the detail object as its argument and store the object in the variable.
      PersonDetail {
       
        public PersonDetail(Person p) {
            person := p;
        }
      }
  2. On the Grid, use the setDetailsGenerator() method to set the detail form to the grid rows.
    c.setDetailsGenerator({ p:Person -> (new PersonDetail(p).getWidget()) });
  3. Send the clicked item to the detail form and toggle the visibility of the detail row.
    c.setItemClickListener({ event:ItemClickEvent ->
      def Object item := event.item;
      c.setDetailsVisible(item, !c.isDetailsVisible(item));
    });
gridDetail.png

Setting Grid Height

By default, the Grid defines a fixed minimum height. You can change the height using the setHeightByRows(), setHeightFull(), or setHeightWrap() method.

c.setHeightByRows(3)

If the grid displays more row objects, the Grid height follows the height setting and a scrollbar is added:

GridWithScroll.png
Grid with a scroll (the height is set to 3 rows and the data source returns 15 row objects

Wrapping Grid Rows

If you want to wrap the Grid around its content so as to adapt the height of the Grid to its content, query the data source size and adapt the height accordingly, for example:

c.setHeightByRows(c.getDataSource().getCount([]))

Displaying a Tooltip on a Grid

You can define a tooltip

  • on the Grid
    myGrid.setDescription({ d:Date -> "The <b>date</b> in the row:" + d}, ContentMode.Html)
  • on the Grid Column

    A column tooltip takes precedence over the Grid tooltip.

    myGridColumn.setDescription({ rowObject:Object -> "Column tooltip"})
  • on the Grid Column header

    myGridColumn.setHeaderDescription(
       "Column header:" + #10 + myGridColumn.getHeader(), 
       ContentMode.Preformatted)
    

    A column tooltip takes precedence over the Grid tooltip.

If the content-mode argument is not passed, all methods use the Preformatted content mode.

Setting Style Class on Grid Rows

To add a style class to grid rows, call the setRowStyleGenerator() method on your grid: the method has a closure parameter with the row object as its input and the CSS class that is added to the row /

element.

c.setRowStyleGenerator({a:Applicant -> "v-label"});

To remove the previously added styles, set the closure to return null, for example, grid.setRowStyleGenerator({a:Applicant -> null});.

Setting Style Class on Grid Columns

To add a style class to the cells of a grid column, call the setCellStyleGenerator() method on your grid column: the method has a closure parameter with the row object as its input and the class.

c.setRowStyleGenerator({a:Applicant -> "v-label"});

To remove the previously added styles, set the closure to return null, for example, grid.setCellStyleGenerator({a:Applicant -> null});.

Defining Content Align on a Grid Column

To define horizontal alignment in Grid Columns, call the setAlignment() method on the column.