12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088 |
- ---
- title: Grid
- order: 24
- layout: page
- ---
-
- [[components.grid]]
- = [classname]#Grid#
-
- ifdef::web[]
- [.sampler]
- image:{live-demo-image}[alt="Live Demo", link="http://demo.vaadin.com/sampler/#ui/grids-and-trees/grid"]
- endif::web[]
-
- [[components.grid.overview]]
- == Overview
-
- [classname]#Grid# is for displaying and editing tabular data laid out in rows
- and columns. At the top, a __header__ can be shown, and a __footer__ at the
- bottom. In addition to plain text, the header and footer can contain HTML and
- components. Having components in the header allows implementing filtering
- easily. The grid data can be sorted by clicking on a column header;
- shift-clicking a column header enables secondary sorting criteria.
-
- [[figure.components.grid.features]]
- .A [classname]#Grid#
- image::img/grid-features.png[width=70%, scaledwidth=100%]
-
- The data area can be scrolled both vertically and horizontally. The leftmost
- columns can be frozen, so that they are never scrolled out of the view. The data
- is loaded lazily from the server, so that only the visible data is loaded. The
- smart lazy loading functionality gives excellent user experience even with low
- bandwidth, such as mobile devices.
-
- The grid data can be edited with a row-based editor after double-clicking a row.
- The fields are set explicitly, and bound to data.
-
- Grid is fully themeable with CSS and style names can be set for all grid
- elements. For data rows and cells, the styles can be generated with a row or
- cell style generator.
-
- Finally, [classname]#Grid# is designed to be extensible and used just as well
- for client-side development - its GWT API is nearly identical to the server-side
- API, including data binding.
-
-
- [[components.grid.data]]
- == Binding to Data
-
- [classname]#Grid# is normally used by binding it to a container data source,
- described in
- <<dummy/../../../framework/datamodel/datamodel-overview.asciidoc#datamodel.overview,"Binding Components to Data">>.
- By default, it is bound to List of items. You can set the items in the constructor or with
- [methodname]#setItems()# method.
-
- For example, if you have a list of beans, you could add to a [classname]#Grid# as follows
-
-
- [source, java]
- ----
- // Have some data
- List<Person> people = Lists.newArrayList(
- new Person("Nicolaus Copernicus", 1543),
- new Person("Galileo Galilei", 1564),
- new Person("Johannes Kepler", 1571));
-
- // Create a grid bound to the list
- Grid<Person> grid = new Grid<>(people);
- grid.addColumn("Name", Person::getName);
- grid.addColumn("Year of birth", Person::getBirthYear);
- layout.addComponent(grid);
- ----
-
- In addition to list you can pass items individually:
-
- [source, java]
- ----
- grid.setItems(new Person("Nicolaus Copernicus", 1543),
- new Person("Galileo Galilei", 1564));
- ----
-
- Note that you can not use [methodname]#addRow()# to add items if the container
- is read-only or has read-only columns, such as generated columns.
-
-
-
- [[components.grid.selection]]
- == Handling Selection Changes
-
- Selection in [classname]#Grid# is handled a bit differently from other selection
- components, as it is not an [classname]#AbstractSelect#. Grid supports both
- single and multiple selection, defined by the __selection model__. Selection
- events can be handled with a [interfacename]#SelectionListener#.
-
- [[components.grid.selection.mode]]
- === Selection Models
-
- A [classname]#Grid# can be set to be in [literal]#++SINGLE++# (default),
- [literal]#++MULTI++#, or [literal]#++NONE++# selection mode, defined in the
- [interfacename]#SelectionMode# enum.
-
-
- [source, java]
- ----
- // Use single-selection mode (default)
- grid.setSelectionMode(SelectionMode.SINGLE);
- ----
-
- Empty (null) selection is allowed by default, but can be disabled
- with [methodname]#setDeselectAllowed()# in single-selection mode.
-
- [source, java]
- ----
- // Pre-select 3rd item from the person list
- grid.select(personList.get(2));
-
- ----
-
-
- [[components.grid.selection.single]]
- === Handling Selection
-
- Changes in the selection can be handled with a
- [interfacename]#SelectionListener#. You need to implement the
- [methodname]#select()# method, which gets a [classname]#SelectionEvent# as
- parameter. In addition to selection, you can handle clicks on rows or cells with
- a [interfacename]#CellClickListener#.
-
- You can get the new selection from the selection event with
- [methodname]#getSelected()#, which returns a set of items, or more simply
- from the grid.
-
- For example:
-
- [source, java]
- ----
- grid.addSelectionListener(selectionEvent -> {
- // Get selection from the selection model
- Collection<Person> selectedPersons =
- selectionEvent.getSelected();
- if (!selectedPersons.isEmpty())
- Notification.show("Selected " + selectedPersons);
- else
- Notification.show("Nothing selected");
- });
- ----
-
- The current selection can be obtained from the [classname]#Grid# object by
- [methodname]#getSelectedItem()# or [methodname]#getSelectedItems()#, which return
- one (in single-selection mode) or all (in multi-selection mode) selected items.
-
-
- [WARNING]
- ====
- If you change the data source for a grid, it will clear the selection. To keep
- the previous selection you must reset the selection afterwards using the
- [methodname]#select()# method.
- ====
-
- [[components.grid.selection.multi]]
- === Multiple Selection
-
- In the multiple selection mode, a user can select multiple items by clicking on
- the checkboxes in the leftmost column, or by using the kbd:[Space] to select/deselect the currently focused row.
- Space bar is the default key for toggling the selection, but it can be customized.
-
- [[figure.components.grid.selection.multi]]
- .Multiple Selection in [classname]#Grid#
- image::img/grid-selection-multi.png[width=50%, scaledwidth=75%]
-
- You can use [methodname]#select()# to add items to the selection.
-
-
- [source, java]
- ----
- // Grid in multi-selection mode
- Grid<Person> grid = Grid<>(personList)
- grid.setSelectionMode(SelectionMode.MULTI);
-
- // Items 2-4
- personList.subList(2,3).forEach(grid::select);
-
- ----
-
- The current selection can be read with [methodname]#getSelected()#
- in the [classname]#Grid#.
-
-
- [source, java]
- ----
- // Allow deleting the selected items
- Button delSelected = new Button("Delete Selected", e -> {
- // Delete all selected data items
- for (Person person: selection.getSelected())
- personList.remove(person);
-
- // Disable after deleting
- e.getButton().setEnabled(false);
-
- // Reset grid content from the list
- grid.setItems(personList);
- });
- delSelected.setEnabled(!grid.getSelected().isEmpty());
- ----
-
- Changes in the selection can be handled with a
- [interfacename]#SelectionListener#. The selection event object provides
- [methodname]#getAdded()# and [methodname]#getRemoved()# to allow determining the
- differences in the selection change.
-
-
- [source, java]
- ----
- // Handle selection changes
- grid.addSelectionListener(selection -> { // Java 8
- Notification.show(selection.getAdded().size() +
- " items added, " +
- selection.getRemoved().size() +
- " removed.");
-
- // Allow deleting only if there's any selected
- deleteSelected.setEnabled(
- grid.getSelectedRows().size() > 0);
- });
- ----
-
-
- [[components.grid.selection.clicks]]
- === Focus and Clicks
-
- In addition to selecting rows, you can focus individual cells. The focus can be
- moved with arrow keys and, if editing is enabled, pressing kbd:[Enter] opens the
- editor. Normally, pressing kbd:[Tab] or kbd:[Shift+Tab] moves the focus to another component,
- as usual.
-
- When editing or in unbuffered mode, kbd:[Tab] or kbd:[Shift+Tab] moves the focus to the next or
- previous cell. The focus moves from the last cell of a row forward to the
- beginning of the next row, and likewise, from the first cell backward to the
- end of the previous row. Note that you can extend [classname]#DefaultEditorEventHandler#
- to change this behavior.
-
- With the mouse, you can focus a cell by clicking on it. The clicks can be handled
- with an [interfacename]#ItemClickListener#. The [classname]#ItemClickEvent#
- object contains various information, most importantly the ID of the clicked row
- and column.
-
-
- [source, java]
- ----
- grid.addCellClickListener(event ->
- Notification.show("Value: " + event.getItem());
- ----
-
- The clicked grid cell is also automatically focused.
-
- The focus indication is themed so that the focused cell has a visible focus
- indicator style by default, while the row does not. You can enable row focus, as
- well as disable cell focus, in a custom theme. See <<components.grid.css>>.
-
-
-
- [[components.grid.columns]]
- == Configuring Columns
-
- Columns are normally defined in the container data source. The
- [methodname]#addColumn()# method can be used to add columns to [classname]#Grid#.
-
- Column configuration is defined in [classname]#Grid.Column# objects, which can
- be obtained from the grid with [methodname]#getColumns()#.
-
-
- [source, java]
- ----
- Column<Date> bornColumn = grid.addColumn(Person:getBirthDate);
- bornColumn.setHeaderCaption("Born date");
-
- ----
-
- In the following, we describe the basic column configuration.
-
- [[components.grid.columns.order]]
- === Column Order
-
- You can set the order of columns with [methodname]#setColumnOrder()# for the
- grid. Columns that are not given for the method are placed after the specified
- columns in their natural order.
-
-
- [source, java]
- ----
- grid.setColumnOrder(firstnameColumn, lastnameColumn,
- bornColumn, birthplaceColumn,
- diedColumn);
- ----
-
- Note that the method can not be used to hide columns. You can hide columns with
- the [methodname]#removeColumn()#, as described later.
-
-
- [[components.grid.columns.removing]]
- === Hiding and Removing Columns
-
- Columns can be hidden by calling [methodname]#setHidden()# in [classname]#Column#.
- Furthermore, you can set the columns user hideable using method
- [methodname]#setHideable()#.
-
- Columns can be removed with [methodname]#removeColumn()# and
- [methodname]#removeAllColumns()#. To restore a previously removed column,
- you can call [methodname]#addColumn()#.
-
- [[components.grid.columns.captions]]
- === Column Captions
-
- Column captions are displayed in the grid header. You can set the header caption
- explicitly through the column object with [methodname]#setHeaderCaption()#.
-
-
- [source, java]
- ----
- Column<Date> bornColumn = grid.addColumn(Person:getBirthDate);
- bornColumn.setHeaderCaption("Born date");
-
- ----
-
- This is equivalent to setting it with [methodname]#setText()# for the header
- cell; the [classname]#HeaderCell# also allows setting the caption in HTML or as
- a component, as well as styling it, as described later in
- <<components.grid.headerfooter>>.
-
-
- [[components.grid.columns.width]]
- === Column Widths
-
- Columns have by default undefined width, which causes automatic sizing based on
- the widths of the displayed data. You can set column widths explicitly by pixel
- value with [methodname]#setWidth()#, or relatively using expand ratios with
- [methodname]#setExpandRatio()#.
-
- When using expand ratios, the columns with a non-zero expand ratio use the extra
- space remaining from other columns, in proportion to the defined ratios.
-
- You can specify minimum and maximum widths for the expanding columns with
- [methodname]#setMinimumWidth()# and [methodname]#setMaximumWidth()#,
- respectively.
-
- The user can resize columns by dragging their separators with the mouse. When resized manually,
- all the columns widths are set to explicit pixel values, even if they had
- relative values before.
-
- [[components.grid.columns.frozen]]
- === Frozen Columns
-
- You can set the number of columns to be frozen with
- [methodname]#setFrozenColumnCount()#, so that they are not scrolled off when
- scrolling horizontally.
-
-
- [source, java]
- ----
- grid.setFrozenColumnCount(2);
- ----
-
- Setting the count to [parameter]#0# disables frozen data columns; setting it to
- [parameter]#-1# also disables the selection column in multi-selection mode.
-
-
-
- [[components.grid.generatedcolumns]]
- == Generating Columns
-
- Columns with values computed from other columns can be simply added by using
- lambdas:
-
- [source, java]
- ----
- // Add generated full name column
- Column<String> fullNameColumn = grid.addColumn(person ->
- person.getFirstName() + " " + person.getLastName());
- fullNameColumn.setHeaderCaption("Full name");
- ----
-
- [[components.grid.renderer]]
- == Column Renderers
-
- A __renderer__ is a feature that draws the client-side representation of a data
- value. This allows having images, HTML, and buttons in grid cells.
-
- [[figure.components.grid.renderer]]
- .Column renderers: image, date, HTML, and button
- image::img/grid-renderers.png[width=75%, scaledwidth=100%]
-
- Renderers implement the [interfacename]#Renderer# interface.
- You set the column renderer in the [classname]#Grid.Column# object as follows:
-
- [source, java]
- ----
-
- Column<Integer> bornColumn = grid.addColumn(Person:getBirthYear);
-
- ...
- Grid.Column bornColumn = grid.getColumn("born");
- bornColumn.setRenderer(new NumberRenderer("born in %d AD"));
- ----
-
- Renderers require a specific data type for the column. To convert to a property
- type to a type required by a renderer, you can pass an optional
- [interfacename]#Converter# to [methodname]#setRenderer()#, as described later in
- this section. A converter can also be used to (pre)format the property values.
- The converter is run on the server-side, before sending the values to the
- client-side to be rendered with the renderer.
-
- The following renderers are available, as defined in the server-side
- [package]#com.vaadin.ui.renderers# package:
-
- [classname]#ButtonRenderer#:: Renders the data value as the caption of a button. A [interfacename]#RendererClickListener# can be given to handle the button clicks.
-
- ifdef::web[]
- +
- Typically, a button renderer is used to display buttons for operating on a data
- item, such as edit, view, delete, etc. It is not meaningful to store the button
- captions in the data source, rather you want to generate them, and they are
- usually all identical.
- +
- [source, java]
- ----
- List<Person> people = new ArrayList<>();
-
- people.add(new Person("Nicolaus Copernicus", 1473));
- people.add(new Person("Galileo Galilei", 1564));
- people.add(new Person("Johannes Kepler", 1571));
-
- // Create a grid
- Grid<Person> grid = new Grid(people);
-
- // Render a button that deletes the data row (item)
- grid.addColumn(person -> "Delete" )
- .setRenderer(new ButtonRenderer(clickEvent -> {
- people.remove(clickEvent.getValue());
- grid.setItems(people);
- });
- ----
- endif::web[]
-
- [classname]#ImageRenderer#:: Renders the cell as an image.
- The column type must be a [interfacename]#Resource#, as described in
- <<dummy/../../../framework/application/application-resources#application.resources,"Images and Other Resources">>; only [classname]#ThemeResource# and
- [classname]#ExternalResource# are currently supported for images in
- [classname]#Grid#.
-
- ifdef::web[]
- +
- [source, java]
- ----
- Column<ThemeResource> imageColumn = grid.addColumn("picture",
- p -> new ThemeResource("img/"+p.getLastname()+".jpg"));
- imageColumn.setRenderer(new ImageRenderer());
- ----
- +
- You also need to define the row heights so that the images fit there. You can
- set it in the theme for all data cells or for the column containing the images.
-
- +
- For the latter way, first define a CSS style name for grid and the column:
-
-
- +
- [source, java]
- ----
- grid.setStyleName("gridwithpics128px");
- imageColumn.setCellStyleGenerator(cell -> "imagecol");
- ----
- ifdef::web[]
- +
- Then, define the style in CSS (Sass):
- endif::web[]
-
-
- +
- [source, css]
- ----
- .gridwithpics128px .imagecol {
- height: 128px;
- background: black;
- text-align: center;
- }
- ----
- endif::web[]
-
- [classname]#DateRenderer#:: Formats a column with a [classname]#Date# type using string formatter. The
- format string is same as for [methodname]#String.format()# in Java API. The date
- is passed in the parameter index 1, which can be omitted if there is only one
- format specifier, such as "[literal]#++%tF++#".
-
- ifdef::web[]
- +
- [source, java]
- ----
- Grid.Column<Date> bornColumn = grid.addColumn(person:getBirthDate);
- bornColumn.setRenderer(
- new DateRenderer("%1$tB %1$te, %1$tY",
- Locale.ENGLISH));
- ----
-
- +
- Optionally, a locale can be given. Otherwise, the default locale (in the
- component tree) is used.
- endif::web[]
-
- [classname]#HTMLRenderer#:: Renders the cell as HTML.
- This allows formatting the cell content, as well as using HTML features such as hyperlinks.
-
- ifdef::web[]
- +
- Set the renderer in the [classname]#Grid.Column# object:
- +
- [source, java]
- ----
- Column<String> htmlColumn grid.addColumn(person ->
- "<a href='" + person.getDetailsUrl() + "' target='_top'>info</a>");
- htmlColumn.setRenderer(new HtmlRenderer());
- ----
- endif::web[]
-
- [classname]#NumberRenderer#:: Formats column values with a numeric type extending [classname]#Number#:
- [classname]#Integer#, [classname]#Double#, etc. The format can be specified
- either by the subclasses of [classname]#java.text.NumberFormat#, namely
- [classname]#DecimalFormat# and [classname]#ChoiceFormat#, or by
- [methodname]#String.format()#.
-
- ifdef::web[]
- +
- For example:
- +
- [source, java]
- ----
- // Define some columns
- Column<String> nameCol = grid.addColumn(person::getName);
- Column<Integer> bornCol = grid.addColumn(person:getBirthYear);
- Column<Integer> slettersCol = grid.addColumn("sletters");
- Column<Double> ratingCol = grid.addColumn("rating");
-
- // Use decimal format
- bornCol.setRenderer(new NumberRenderer(
- new DecimalFormat("in #### AD")));
-
- // Use textual formatting on numeric ranges
- slettersCol.setRenderer(new NumberRenderer(
- new ChoiceFormat("0#none|1#one|2#multiple")));
-
- // Use String.format() formatting
- ratingCol.setRenderer(new NumberRenderer(
- "%02.4f", Locale.ENGLISH));
-
- // Add some data rows
- grid.addItems(new Person("Nicolaus Copernicus", 1473, 2, 0.4),
- new Person("Galileo Galilei", 1564, 0, 4.2),
- new Person("Johannes Kepler", 1571, 1, 2.3));
-
- ----
- endif::web[]
- [classname]#ProgressBarRenderer#:: Renders a progress bar in a column with a [classname]#Double# type. The value
- must be between 0.0 and 1.0.
-
- ifdef::web[]
- +
- For example:
- +
- [source, java]
- ----
- // Define some columns
- Column<String> nameCol = grid.addColumn(person::getName);
- Column<Double> ratingCol = grid.addColumn("rating");
- ratingCol.setRenderer(new ProgressBarRenderer());
-
- // Add some data rows
- grid.addItems(new Person("Nicolaus Copernicus", 0.4),
- new Person("Galileo Galilei", 4.2),
- new Person("Johannes Kepler", 2.3));
- ----
- endif::web[]
- [classname]#TextRenderer#:: Displays plain text as is. Any HTML markup is quoted.
-
-
-
- [[components.grid.renderer.custom]]
- === Custom Renderers
-
- Renderers are component extensions that require a client-side counterpart. See
- <<dummy/../../../framework/clientsidewidgets/clientsidewidgets-grid#clientsidewidgets.grid.renderers,"Renderers">>
- for information on implementing custom renderers.
-
-
- [[components.grid.headerfooter]]
- == Header and Footer
-
- A grid by default has a header, which displays column names, and can have a
- footer. Both can have multiple rows and neighbouring header row cells can be
- joined to feature column groups.
-
- [[components.grid.headerfooter.adding]]
- === Adding and Removing Header and Footer Rows
-
- A new header row is added with [methodname]#prependHeaderRow()#, which adds it
- at the top of the header, [methodname]#appendHeaderRow()#, which adds it at the
- bottom of the header, or with [methodname]#addHeaderRowAt()#, which inserts it
- at the specified 0-base index. All of the methods return a
- [classname]#HeaderRow# object, which you can use to work on the header further.
-
-
- [source, java]
- ----
- // Group headers by joining the cells
- HeaderRow groupingHeader = grid.prependHeaderRow();
- ...
-
- // Create a header row to hold column filters
- HeaderRow filterRow = grid.appendHeaderRow();
- ...
- ----
-
- Similarly, you can add footer rows with [methodname]#appendFooterRow()#,
- [methodname]#prependFooterRow()#, and [methodname]#addFooterRowAt()#.
-
-
- [[components.grid.headerfooter.joining]]
- === Joining Header and Footer Cells
-
- You can join two or more header or footer cells with the [methodname]#join()#
- method. For header cells, the intention is usually to create column grouping,
- while for footer cells, you typically calculate sums or averages.
-
-
- [source, java]
- ----
- // Group headers by joining the cells
- HeaderRow groupingHeader = grid.prependHeaderRow();
- HeaderCell namesCell = groupingHeader.join(
- groupingHeader.getCell("firstname"),
- groupingHeader.getCell("lastname")).setText("Person");
- HeaderCell yearsCell = groupingHeader.join(
- groupingHeader.getCell("born"),
- groupingHeader.getCell("died"),
- groupingHeader.getCell("lived")).setText("Dates of Life");
- ----
-
-
- [[components.grid.headerfooter.content]]
- === Text and HTML Content
-
- You can set the header caption with [methodname]#setText()#, in which case any
- HTML formatting characters are quoted to ensure security.
-
-
- [source, java]
- ----
- HeaderRow mainHeader = grid.getDefaultHeaderRow();
- mainHeader.getCell("firstname").setText("First Name");
- mainHeader.getCell("lastname").setText("Last Name");
- mainHeader.getCell("born").setText("Born In");
- mainHeader.getCell("died").setText("Died In");
- mainHeader.getCell("lived").setText("Lived For");
- ----
-
- To use raw HTML in the captions, you can use [methodname]#setHtml()#.
-
-
- [source, java]
- ----
- namesCell.setHtml("<b>Names</b>");
- yearsCell.setHtml("<b>Years</b>");
- ----
-
-
- [[components.grid.headerfooter.components]]
- === Components in Header or Footer
-
- You can set a component in a header or footer cell with
- [methodname]#setComponent()#. Often, this feature is used to allow filtering, as
- described in <<components.grid.filtering>>, which also gives an example of the
- use.
-
- [[components.grid.filtering]]
- == Filtering
-
- The ability to include components in the grid header can be used to create
- filters for the grid data. Filtering is done in the container data source, so
- the container must be of type that implements
- [interfacename]#Container.Filterable#.
-
- [[figure.components.grid.filtering]]
- .Filtering Grid
- image::img/grid-filtering.png[width=50%, scaledwidth=80%]
-
- The filtering illustrated in <<figure.components.grid.filtering>> can be created
- as follows:
-
- [source, java]
- ----
- // Have a list of persons
- List<Person> persons = exampleDataSource();
-
- // Create a grid bound to it
- Grid<Person> grid = new Grid(persons);
- grid.setSelectionMode(SelectionMode.NONE);
- grid.setWidth("500px");
- grid.setHeight("300px");
-
- // Create a header row to hold column filters
- HeaderRow filterRow = grid.appendHeaderRow();
-
- // Set up a filter for all columns
- for (Column<?> col: grid.getColumns()) {
- HeaderCell cell = filterRow.getCell(col);
-
- // Have an input field to use for filter
- TextField filterField = new TextField();
-
- // Update filter When the filter input is changed
- filterField.addValueChangeListener(event -> {
-
- // Filter the list of items
- List<String> filteredList =
- Lists.newArrayList(personList.filter(persons,
- Predicates.containsPattern(event.getValue())));
-
- // Apply filtered data
- grid.setItems(filteredList);
-
- });
- cell.setComponent(filterField);
-
- }
- ----
-
- [[components.grid.sorting]]
- == Sorting
-
- A user can sort the data in a grid on a column by clicking the column header.
- Clicking another time on the current sort column reverses the sort direction.
- Clicking on other column headers while keeping the Shift key pressed adds a
- secondary or more sort criteria.
-
- [[figure.components.grid.sorting]]
- .Sorting Grid on Multiple Columns
- image::img/grid-sorting.png[width=50%, scaledwidth=75%]
-
- Defining sort criteria programmatically can be done with the various
- alternatives of the [methodname]#sort()# method. You can sort on a specific
- column with [methodname]#sort(Column column)#, which defaults to ascending
- sorting order, or [methodname]#sort(Column column, SortDirection
- direction)#, which allows specifying the sort direction.
-
-
- [source, java]
- ----
- grid.sort(nameColumn, SortDirection.DESCENDING);
- ----
-
- To sort on multiple columns, you need to use the fluid sort API with
- [methodname]#sort(Sort)#, which allows chaining sorting rules. Sorting rules are
- created with the static [methodname]#by()# method, which defines the primary
- sort column, and [methodname]#then()#, which can be used to specify any
- secondary sort columns. They default to ascending sort order, but the sort
- direction can be given with an optional parameter.
-
-
- [source, java]
- ----
- // Sort first by city and then by name
- grid.sort(Sort.by(cityColumn, SortDirection.ASCENDING)
- .then(nameColumn, SortDirection.DESCENDING));
- ----
-
- [[components.grid.editing]]
- == Editing
-
- Grid supports line-based editing, where double-clicking a row opens the row
- editor. In the editor, the input fields can be edited, as well as navigated with
- kbd:[Tab] and kbd:[Shift+Tab] keys. If validation fails, an error is displayed and the user
- can correct the inputs.
-
- To enable editing, you need to call [methodname]#setEditorEnabled(true)# for the
- grid.
-
-
- [source, java]
- ----
- Grid<Person> grid = new Grid(persons);
- grid.setEditorEnabled(true);
- ----
-
- Grid supports two row editor modes - buffered and unbuffered. The default mode is
- buffered. The mode can be changed with [methodname]#setBuffered(false)#
-
- [[components.grid.editing.buffered]]
- === Buffered Mode
-
- The editor has a [guibutton]#Save# button that commits
- the data item to the container data source and closes the editor. The
- [guibutton]#Cancel# button discards the changes and exits the editor.
-
- A row under editing is illustrated in <<figure.components.grid.editing>>.
-
- [[figure.components.grid.editing]]
- .Editing a Grid Row
- image::img/grid-editor-basic.png[width=50%, scaledwidth=75%]
-
- [[components.grid.editing.unbuffered]]
- === Unbuffered Mode
-
- The editor has no buttons and all changed data is committed directly
- to the container. If another row is clicked, the editor for the current row is closed and
- a row editor for the clicked row is opened.
-
- [[components.grid.editing.fields]]
- === Editor Fields
-
- The editor fields are configured in [classname]#Column#and bound to
- the bean data source with a [classname]#Binder#, which
- also handles tasks such as validation, as explained later.
-
- To disable editing in a particular column, you can call
- [methodname]#setEditorField()# in the [classname]#Column# object with
- [parameter]#null# parameter.
-
- In the following example, we configure a field with validation and styling:
-
-
- [source, java]
- ----
- // Create an editor for name
- TextField nameEditor = new TextField();
-
- // Custom CSS style
- nameEditor.addStyleName("nameeditor");
-
- // Add editor to name column
- nameColumn.setEditorField(nameEditor);
- ----
-
- Setting an editor field to [parameter]#null# deletes the currently existing
- editor field and makes the column non-editable.
-
-
- ifdef::web[]
- [[components.grid.editing.captions]]
- === Customizing Editor Buttons
-
- In the buffered mode, the editor has two buttons: [guibutton]#Save# and [guibutton]#Cancel#. You can
- set their captions with [methodname]#setEditorSaveCaption()# and
- [methodname]#setEditorCancelCaption()#, respectively.
-
- In the following example, we demonstrate one way to translate the captions:
-
-
- [source, java]
- ----
- // Captions are stored in a resource bundle
- ResourceBundle bundle = ResourceBundle.getBundle(
- MyAppCaptions.class.getName(),
- Locale.forLanguageTag("fi")); // Finnish
-
- // Localize the editor button captions
- grid.setEditorSaveCaption(
- bundle.getString(MyAppCaptions.SaveKey));
- grid.setEditorCancelCaption(
- bundle.getString(MyAppCaptions.CancelKey));
- ----
-
- endif::web[]
-
- [[components.grid.editing.fieldgroup]]
- === Binding to Data with a Binder
-
- Data binding to the item under editing is handled with a
- [classname]#Binder#, which you need to set with
- [methodname]#setEditorFieldGroup#. This is mostly useful when using
- special-purpose, such as to enable bean validation.
-
- For example, assuming that we want to enable bean validation for a bean such as
- the following:
-
-
- [source, java]
- ----
- public class Person implements Serializable {
- @NotNull
- @Size(min=2, max=10)
- private String name;
-
- @Min(1)
- @Max(130)
- private int age;
- ...]
- ----
-
- We can now use a [classname]#BeanBinder# in the [classname]#Grid# as
- follows:
-
- [source, java]
- ----
- Grid<Person> grid = new Grid(examplePersonList());
- Column<String> nameCol = grid.addColumn(Person::getName);
- Column<Integer> ageCol = grid.addColumn(Person::getAge);
- grid.setEditorEnabled(true);
-
- TextField nameEditor = new TextField();
- nameCol.setEditorField(nameEditor);
-
- // Enable bean validation for the data
- BeanBinder<Person> binder = new BeanBinder<>(Person.class);
-
- // Have some extra validation in a field
- binder.addField(nameEditor, "name")
- .addValidator(new RegexpValidator(
- "^\\p{Alpha}+ \\p{Alpha}+$",
- "Need first and last name"));
-
- grid.setEditorBinder(binder);
-
- ----
-
- To use bean validation as in the example above, you need to include an
- implementation of the Bean Validation API in the classpath, as described in
- <<dummy/../../../framework/datamodel/datamodel-itembinding#datamodel.itembinding.beanvalidation,"Bean
- Validation">>.
-
-
- ifdef::web[]
- [[components.grid.editing.validation]]
- === Handling Validation Errors
-
- The input fields are validated when the value is updated. The default
- error handler displays error indicators in the invalid fields, as well as the
- first error in the editor.
-
- [[figure.components.grid.errors]]
- .Editing a Grid Row
- image::img/grid-editor-errors.png[width=50%, scaledwidth=75%]
-
- You can modify the error handling by implementing a custom
- [interfacename]#EditorErrorHandler# or by extending the
- [classname]#DefaultEditorErrorHandler#.
-
- endif::web[]
-
-
- [[components.grid.scrolling]]
- == Programmatic Scrolling
-
- You can scroll to first item with [methodname]#scrollToStart()#, to end with
- [methodname]#scrollToEnd()#, or to a specific row with [methodname]#scrollTo()#.
-
-
- [[components.grid.stylegeneration]]
- == Generating Row or Cell Styles
-
- You can style entire rows or individual cells with a
- [interfacename]#StyleGenerator#, typically used through Java lambdas.
-
- [[components.grid.stylegeneration.row]]
- === Generating Row Styles
-
- You set a [interfacename]#StyleGenerator# to a grid with
- [methodname]#setStyleGenerator()#. The [methodname]#getStyle()# method gets a
- date item, and should return a style name or [parameter]#null# if
- no style is generated.
-
- For example, to add a style names to rows having certain values in one
- property of an item, you can style them as follows:
-
-
- [source, java]
- ----
- grid.setStyleGenerator(person -> {
- // Style based on alive status
- person.isAlive() ? null : "dead";
- });
- ----
-
- You could then style the rows with CSS as follows:
-
-
- [source, css]
- ----
- .v-grid-row.dead {
- color: gray;
- }
- ----
-
-
- [[components.grid.stylegeneration.cell]]
- === Generating Cell Styles
-
- You set a [interfacename]#StyleGenerator# to a grid with
- [methodname]#setStyleGenerator()#. The [methodname]#getStyle()# method gets
- a [classname]#CellReference#, which contains various information about the cell
- and a reference to the grid, and should return a style name or [parameter]#null#
- if no style is generated.
-
- For example, to add a style name to a specific column, you can match on
- the column as follows:
-
-
- [source, java]
- ----
- // Static style based on column
- bornColumn.setStyleGenerator(person -> "rightalign");
- ----
-
- You could then style the cells with a CSS rule as follows:
-
-
- [source, css]
- ----
- .v-grid-cell.rightalign {
- text-align: right;
- }
- ----
-
-
-
- [[components.grid.css]]
- == Styling with CSS
-
-
- [source, css]
- ----
- .v-grid {
- .v-grid-scroller, .v-grid-scroller-horizontal { }
- .v-grid-tablewrapper {
- .v-grid-header {
- .v-grid-row {
- .v-grid-cell, .frozen, .v-grid-cell-focused { }
- }
- }
- .v-grid-body {
- .v-grid-row,
- .v-grid-row-stripe,
- .v-grid-row-has-data {
- .v-grid-cell, .frozen, .v-grid-cell-focused { }
- }
- }
- .v-grid-footer {
- .v-grid-row {
- .v-grid-cell, .frozen, .v-grid-cell-focused { }
- }
- }
- }
- .v-grid-header-deco { }
- .v-grid-footer-deco { }
- .v-grid-horizontal-scrollbar-deco { }
- .v-grid-editor {
- .v-grid-editor-cells { }
- .v-grid-editor-footer {
- .v-grid-editor-message { }
- .v-grid-editor-buttons {
- .v-grid-editor-save { }
- .v-grid-editor-cancel { }
- }
- }
- }
- }
- ----
-
- A [classname]#Grid# has an overall [literal]#++v-grid++# style. The actual grid
- has three parts: a header, a body, and a footer. The scrollbar is a custom
- element with [literal]#++v-grid-scroller++# style. In addition, there are some
- decoration elements.
-
- Grid cells, whether thay are in the header, body, or footer, have a basic
- [literal]#++v-grid-cell++# style. Cells in a frozen column additionally have a
- [literal]#++frozen++# style. Rows have [literal]#++v-grid-row++# style, and
- every other row has additionally a [literal]#++v-grid-row-stripe++# style.
-
- The focused row has additionally [literal]#++v-grid-row-focused++# style and
- focused cell [literal]#++v-grid-cell-focused++#. By default, cell focus is
- visible, with the border stylable with [parameter]#$v-grid-cell-focused-border#
- parameter in Sass. Row focus has no visible styling, but can be made visible
- with the [parameter]#$v-grid-row-focused-background-color# parameter or with a
- custom style rule.
-
- In editing mode, a [literal]#++v-grid-editor++# overlay is placed on the row
- under editing. In addition to the editor field cells, it has an error message
- element, as well as the buttons.
-
-
- ((()))
|