This post is part of a series about the DevExtreme React Grid. You can find the introduction and overview to the post series by following this link.
Out of the box, the React Grid comes with several plugins that enable certain control behavior. In a later post, I will show how these plugins can be controlled from React, but for now I will take advantage of the internal functionality of the plugins. Sometimes the term uncontrolled is used for this scenario, hinting at the fact that there is no external influence on a component’s behavior.
Note for clarity that there is one component that is already controlled at this point: the Grid
itself, which receives values for its rows
and columns
from my code.
Plugin categories
All the standard plugins can be sorted into three categories. For details on each plugin that I don’t mention here, please check out the documentation. I will not mention every plugin by name, since I expect the list to change as development progresses.
State
The first category is that of state. All state plugins have names ending in State
, like FilteringState
and PagingState
. These plugins need to be added to the Grid
first, i.e. before any plugins from the other categories below.
State plugins provide fields and events for situations where state will be stored elsewhere (the controlled mode mentioned above), and for the uncontrolled mode I’m describing now, they may have defaultXXX
fields that enable you to preset the state.
In my sample, shown at the bottom of this post, I’m using all the currently supported state plugins:
<SortingState defaultSorting={[{ columnName: "name", direction: "asc" }]} /><PagingState /><FilteringState /><GroupingState /><EditingState onCommitChanges={this.commitChanges} /><SelectionState /><RowDetailState /><ColumnOrderState defaultOrder={["name", "artist", "year"]} />
This configuration supplies default options to two of the plugins, and I’m implementing one of the events to support data saving functionality.
State plugins are imported from DevExpress.ReactGrid
in my browser sample, or from @devexpress/dx-react-grid
in an app that uses a build environment. State plugins do not implement any UI specific or visualization functionality.
Local functionality
I’ll call the second category local functionality. The plugins of this kind supply implementations of grid features, like grouping and sorting. They do this “locally”, i.e. without interaction with a remote service. While there may be configurable options for these plugins, the general idea is to provide out-of-the-box functionality, like our grid components do on other platforms.
The local functionality plugins depend on the state plugins from above. For example, you cannot use the LocalPaging
plugin if you haven’t also added the PagingState
. LocalPaging
must appear after PagingState
to satisfy the dependency.
In my sample, I’m using all currently available local functionality plugins without further configuration:
<LocalSorting /><LocalFiltering /><LocalGrouping /><LocalPaging />
Local functionality plugins are imported in the same way as state plugins, since they also don’t supply visualization functionality.
Visualization
The final category is that of visualization. Plugins in this category are responsible for the rendering of UI elements and information.
Many of these plugins provide options to configure their behavior, and to enable and disable certain features. Some of the plugins also offer options to customize templates they use to render themselves.
The plugins usually have dependencies, and these may include other plugins from the visualization category. For example, the TableHeaderRow
depends on the TableView
, but it can also utilize information from SortingState
and GroupingState
(state plugins) as well as DragDropContext
(a visualization plugin). Details on dependencies can be found in their documentation (for instance here for TableHeaderRow).
Here are the plugins I’m using in my sample. You can see several options, including one to customize a template.
<DragDropContext /><TableView allowColumnReordering /><TableHeaderRow allowSorting allowGrouping allowDragging /><TableFilterRow /><TableGroupRow /><TableSelection highlightSelected showSelectAll /><TableEditRow /><TableEditColumn allowAdding allowEditing allowDeleting /><TableRowDetail template={this.tableRowDetailTemplate} /><PagingPanel allowedPageSizes={[0, 5, 10, 20]} /><GroupingPanel allowSorting />
For visualization plugins, order is particularly important. Of course they mostly have to appear after the state and local functionality plugins, but there are also category-internal dependencies. Most plugins must appear after TableView
, but even TableView
depends on DragDropContext
, which is why the latter is listed first in the sample code.
Note that there is one plugin I’m not using in my sample, which is called VirtualTableView
. This provides an alternative to the standard TableView
, implementing virtual scrolling.
Plugins of the visualization category are specific to the UI library you use. In my sample, I’m using Bootstrap 3, so these plugins are imported from DevExpress.DXReactGridBootstrap3
or @devexpress/dx-react-grid-bootstrap3
. Other UI libraries will be supported in the future, with Material UI being closest to completion. If you use a different supported UI library, you need to import the types from a different source.
Note that in some cases it is possible to accidentally import a type from wrong package. For instance, DragDropContext
also exists in DevExpress.DXReactGrid
or @devexpress/dx-react-grid
. You will receive console error messages due to missing templates if you import a visualization plugin from the wrong package.
Other sample functionality
The sample code implements a template that is used to configure TableRowDetail
. This plugin shows an expansion arrow next to each row, and the template renders the content shown if the user expands a row. For real-world applications, this feature enables all sorts of complicated master/detail scenarios, since the template can render whatever you like. For my sample, I chose to use a simple line of output to demonstrate the feature:
tableRowDetailTemplate({ row }) { return <div>Details about '{row.name}' by {row.artist}</div>; }
A helper function called getRowId
is implemented to retrieve a unique id value from a row of data:
getRowId(row) { return row.id; }
This function configured for the Grid
component itself. Various plugins may require ids for individual rows, and you will generally have to supply a helper function to extract whatever value (or combination of values) you would like to use to identify rows.
Finally, the sample implements data persistence in component state, in the commitChanges
function. The function is configured as the event handler for the onCommitChanges
event on the EditingState
, so it is executed when the user adds or edits a row and clicks Save, or when the Delete link is used. The details of the inner workings are not relevant and the implementation is supplied only for demonstration purposes.
Note that the commitChanges
function is bound to the this
context of the App
class in the constructor, so the function has access to the App
component state.
Try it
Here is the CodePen for the sample described above: