- EGroupware
- Overview
- Configuring the datagrid from an owner widget
- RowProvider
- DataProviders
- Presentation hooks (owner-facing properties)
- Minimal owner widget wiring
- Row templates: columns and rows
- Columns
- Rows
- Row data bindings
- State Templates
- Styling row contents
- Static Widget Style
- Static Widget Internals
- Static Exported Parts
- Dynamic Row Class
- Dynamic Widget Class
- Dynamic CSS Property
- Built-in row sizing properties
- Lifecycle (class internals)
- Construction
- First paint
- Structural change detection
- Data-load trigger
- Fetch
- Row generation
- Hydration (deferred row binding)
- Refresh and reload
- Rendering pipeline (summary)
- Key methods
- Customization points and overrides
- rowCustomizer
- expansionConfig (expandable rows)
- dataProvider override
- Row-scoped deferred attributes (rowTemplateAttrMap)
- Column hide expressions and headers
- Child-grid and layout flags
- Slots
- Properties
- Events
- Methods
- Custom Properties
- Parts
Datagrid
<et2-datagrid> | Et2Datagrid
Virtualized data grid for infinite rows with column sizing, selection, and lazy paging.
et2-datagrid is the low-level, virtualized row renderer used by owner widgets such as
et2-nextmatch. It should stay generic: owners supply structure and data, while the datagrid
owns virtualization, row DOM creation, selection state, keyboard navigation, column layout, loaders,
no-results rendering, and refresh application.
Overview
Configuring the datagrid from an owner widget
Minimal owner widget wiring
Row templates: columns and rows
Row data bindings
Styling row contents
Lifecycle (class internals)
Rendering pipeline (summary)
Key methods
Customization points and overrides
If you are wiring et2-datagrid into another Et2 widget, start with
Configuring the datagrid from an owner widget,
Minimal owner widget wiring,
Key methods, and
Customization points and overrides. The lifecycle section
is for maintainers changing datagrid internals.
Overview
Et2Datagrid is the reusable grid engine under higher-level list widgets. It renders large,
incrementally-loaded datasets by combining Lit rendering with @lit-labs/virtualizer, then adds
the grid behavior EGroupware lists need: column sizing and visibility, row selection, keyboard focus,
loading and empty states, row refreshes, and optional expanded rows.
It is deliberately not an application widget. It does not know what a filter means, how a server endpoint is
called, how a named eTemplate is resolved, or how an application response should be interpreted. Those
responsibilities stay in an owner widget such as et2-nextmatch and in the owner’s template/data
adapters.
Use et2-nextmatch when you need the standard EGroupware list widget with filters, actions,
preferences, and legacy Nextmatch compatibility. Use et2-datagrid directly only when another
Et2 webcomponent needs the same virtualized grid mechanics but owns its own application-level behavior.
Configuring the datagrid from an owner widget
An owner widget configures the datagrid by passing:
-
columns— normalized column metadata used for headers, column widths, visibility, and row layout. -
templateData— prepared row, loader, and attribute-map data, usually produced byEt2RowProvider. -
dataProvider— anEt2DatagridDataProviderimplementation for paged loading and row refreshes. -
Optional presentation hooks such as
rowCustomizer,selectionMode,expansionConfig, and preloaded rows.
Keep app-specific concerns in the owner widget or its provider. The datagrid receives normalized columns, rows, and row templates; it does not resolve application templates, filters, or response payloads itself. It asks the configured provider for already-normalized rows.
RowProvider
Et2RowProvider is the template adapter between an owner widget and the datagrid. It reads
either a named eTemplate or slotted markup and returns Et2DatagridTemplateData.
Its responsibilities include:
- finding the effective header and row template markup
- extracting column metadata from headers
- normalizing legacy row wrappers such as
<row>into datagrid-renderable markup - preparing a reusable
HTMLTemplateElementfor rows - converting row widgets to readonly display behaviour where needed
- recording row-scoped widget attributes in
rowTemplateAttrMap - preparing optional loader and no-results template data
Et2RowProvider does not fetch row data. It prepares the shape used to render rows once data is
available.
DataProviders
Et2DatagridDataProvider is the data boundary for the datagrid. A provider supplies rows in the
datagrid’s normalized shape:
{
id: string;
data: any;
}
The required provider methods are:
-
fetchPage(start, pageSize)— load a page of rows and optionally return the total row count. -
refresh(rowIds, type)— resolve updated rows and removed row ids for refresh operations. -
normalizeRowId(rowId, ensurePrefix)— convert ids to the datastore form used by the rendered grid. -
toProviderRowId(dataStoreRowId)— convert rendered/datastore ids back to the provider’s native row id.
Et2DatagridRow.id should be the stable id the grid uses for selection, duplicate suppression,
refresh matching, and rendered data-row-id attributes. Providers that work with
application-native ids should normalize them in fetchPage() / refresh() and use
toProviderRowId() when they need to call back into the application or server with the native
id.
Optional methods such as getQuerySignature() and getDataStorePrefix() let the
datagrid detect query changes and keep row ids stable across paging, refreshes, nested grids, and action
handling.
Et2NextmatchDataProvider is the Nextmatch implementation. It adapts
egw.dataFetch() and egw.dataRegisterUID() into the generic provider interface,
processes extra Nextmatch response data such as select options and filter values, reads refreshed rows back
from the central UID cache, and supports child-grid providers for expandable rows.
Presentation hooks (owner-facing properties)
| Property | Type | Purpose |
|---|---|---|
columns |
Et2DatagridColumn[] |
Visible column configuration, including sizing and optional hide expressions. |
dataProvider |
Et2DatagridDataProvider | null |
Paging adapter used by infinite scroll. |
templateData |
Et2DatagridTemplateData | null |
Prepared template and metadata used to render each row. |
rowIdField |
string ("id") |
Row-data field that contains the application row id. |
rowCustomizer |
Et2DatagridRowCustomizer | null |
Per-row hook for row/meta-cell presentation tweaks. |
selectionMode |
"none" | "single" | "multiple" |
Row selection behavior (default "multiple"). |
expansionConfig |
Et2DatagridExpansionConfig | null |
Generic expanded-row hooks. |
view |
"row" | "tile" |
Visual layout mode. |
pageSize |
number (50) |
Maximum rows requested per page load. |
rowStylesheets |
CSSStyleSheet[] |
Stylesheets adopted into the row shadow DOM. |
Child-grid / layout flags are covered in Customization points.
Minimal owner widget wiring
Most application code should use et2-nextmatch directly. Use et2-datagrid from
another Et2 webcomponent when the owner needs datagrid mechanics but has its own way to prepare templates,
columns, filters, and data.
The owner is responsible for:
- creating an
Et2RowProviderwith the owner as host, -
resolving
Et2DatagridTemplateDatafrom a named template or from the owner’s light-DOM slots, -
rendering
et2-datagridwith property bindings for columns, template data, and data provider, -
calling
reload()after configuration is ready, orsetInitialRows()when rows were already loaded.
This is the minimal pattern used by an Et2 owner widget with slotted column/row templates:
import {html, LitElement, PropertyValues} from "lit";
import {customElement} from "lit/decorators/custom-element.js";
import {state} from "lit/decorators/state.js";
import {Et2Widget} from "../Et2Widget/Et2Widget";
import {Et2Datagrid} from "./Et2Datagrid";
import {Et2RowProvider} from "./Et2RowProvider";
import type {
Et2DatagridColumn,
Et2DatagridDataProvider,
Et2DatagridSelectionDetail,
Et2DatagridTemplateData
} from "./Et2Datagrid.types";
@customElement("my-grid-owner")
export class MyGridOwner extends Et2Widget(LitElement)
{
private readonly _rowProvider = new Et2RowProvider(this);
@state()
private _templateData : Et2DatagridTemplateData | null = null;
@state()
private _columns : Et2DatagridColumn[] = [];
@state()
private _configurationLoading = true;
private _dataProvider : Et2DatagridDataProvider = new MyProvider();
private get _datagrid() : Et2Datagrid | null
{
return this.shadowRoot?.querySelector("et2-datagrid") as Et2Datagrid | null;
}
private _handleSelectionChanged(event : CustomEvent<Et2DatagridSelectionDetail>)
{
this.dispatchEvent(new CustomEvent("my-grid-selection-changed", {
detail: event.detail,
bubbles: true,
composed: true
}));
}
private _handleActiveRowChanged(event : CustomEvent<{activeRowId : string | null; activeRowIndex : number}>)
{
this.dispatchEvent(new CustomEvent("my-grid-active-row-changed", {
detail: event.detail,
bubbles: true,
composed: true
}));
}
private _handleColumnsChanged(event : CustomEvent<{columns : Et2DatagridColumn[]}>)
{
this._columns = event.detail.columns;
}
private _handleLoadingError()
{
this.dispatchEvent(new CustomEvent("my-grid-loading-error", {
bubbles: true,
composed: true
}));
}
async firstUpdated(changedProperties : PropertyValues)
{
super.firstUpdated(changedProperties);
const templateData = await this._rowProvider.fromSlots();
this._templateData = templateData;
this._columns = templateData?.columns || [];
this._configurationLoading = false;
await this.updateComplete;
await this._datagrid?.reload();
}
render()
{
return html`
<et2-datagrid
._parent=${this}
.columns=${this._columns}
.templateData=${this._templateData}
.dataProvider=${this._dataProvider}
.configurationLoading=${this._configurationLoading}
row-id-field="id"
selection-mode="multiple"
@et2-selection-changed=${this._handleSelectionChanged}
@et2-active-row-changed=${this._handleActiveRowChanged}
@et2-columns-changed=${this._handleColumnsChanged}
@et2-loading-error=${this._handleLoadingError}
>
<slot name="noResults" slot="noResults"></slot>
</et2-datagrid>
`;
}
}
The provider class is implemented separately; see
dataProvider override for the minimal contract. Owners
commonly listen to et2-selection-changed, et2-active-row-changed,
et2-columns-changed, and loading events when they need to synchronize outer action state,
focus, preferences, or error handling.
The slotted markup belongs to the owner element, not directly to et2-datagrid;
Et2RowProvider reads these slots from its host:
<my-grid-owner>
<tr class="th" slot="columns">
<et2-nextmatch-header id="title" label="Title"></et2-nextmatch-header>
<et2-nextmatch-header id="owner" label="Owner"></et2-nextmatch-header>
</tr>
<tr class="$class" slot="row">
<et2-description id="title" noLang="1"></et2-description>
<et2-description id="owner" noLang="1"></et2-description>
</tr>
</my-grid-owner>
._parent=${this} is needed for Et2Widget-owned grids that rely on the owner widget’s array
manager context during row hydration. Et2Nextmatch uses the same binding for its root grid.
If rows are already available, seed the grid instead of fetching the first page:
await this.updateComplete;
this._datagrid?.setInitialRows(preloadedRows);
For named eTemplates, replace fromSlots() with fromTemplate(templateName):
const templateData = await this._rowProvider.fromTemplate("myapp.index.rows");
Row templates: columns and rows
Columns
Columns are derived from header widgets/elements and include key, title, and optional width/minWidth/disabled metadata.
From Named Templates
When using et2-nextmatch template="app.index.rows":
-
Header definition is parsed from the template header row (
.th,thead, or grid header structure). -
Column widgets (such as
et2-nextmatch-header,et2-nextmatch-sortheader) are used to build column definitions. - Legacy Nextmatch visibility/size preferences are mapped and applied by
et2-nextmatch.
From Slotted Templates
When using slots (template attribute not set):
- Columns come from
slot="columns". - Any wrapper can carry the slot (
tr,div,et2-box, etc.). - The columns wrapper itself is not treated as a column; its child elements are used as column definitions.
Example:
<et2-nextmatch>
<tr class="th" slot="columns">
<et2-nextmatch-sortheader id="n_family" label="Name"></et2-nextmatch-sortheader>
<et2-nextmatch-header id="note" label="Note"></et2-nextmatch-header>
<et2-vbox>
<et2-nextmatch-header id="tel_work" label="Business phone"></et2-nextmatch-header>
<et2-nextmatch-header id="tel_cell" label="Mobile phone"></et2-nextmatch-header>
<et2-nextmatch-header id="tel_home" label="Home phone"></et2-nextmatch-header>
</et2-vbox>
</tr>
<tr slot="row">...</tr>
</et2-nextmatch>
Rows
Row rendering is driven by a row template.
- The row template is not given any server-side processing when the template is initially loaded.
- Avoid legacy widgets in the row template.
Row data bindings
Use direct bindings for row data in templates:
$fieldresolves an own field of the current row.$[parent.child]resolves a nested row path.-
$rowis reserved for renderers that need the complete row context, such as VFS and customfields row renderers. For value-capable renderers it receives the row object; other uses retain the row id/key.
The datagrid resolves direct row bindings before transformAttributes(). This avoids an ArrayMgr
row perspective for the usual row and lets widgets receive concrete values. Non-row expressions remain in
the normal manager context: $cont[...], _cont, @..., and
@@... are not row bindings.
<row class="$class $[category.css_class]">
<et2-description id="title" noLang="1"></et2-description>
<et2-date-time id="modified" value="$[timestamps.modified]" readonly="true"></et2-date-time>
<et2-image src="$icon" label="$type_label"></et2-image>
<et2-date-duration disabled="!$used_time" value="$duration"></et2-date-duration>
<et2-hbox onclick="egw.open($id, 'infolog');"></et2-hbox>
</row>
For value-capable row widgets, a simple id="title" remains the widget id and is hydrated from
rowData.title when that own field exists and no explicit value is present. Use
value="$field" for a differently named or nested row value. Compound/action ids such as
edit_status[$id] remain ids and are not value bindings.
Legacy row syntax remains supported without changing existing templates:
<!-- Legacy compatibility: equivalent to id="title" -->
<et2-description id="${row}[title]" noLang="1"></et2-description>
<et2-description id="$row_cont[title]" noLang="1"></et2-description>
When direct resolution cannot safely handle an expression, the datagrid retains the ArrayMgr perspective compatibility path. Do not add new row templates that depend on that fallback.
From Named Templates
Named row templates are normalized from legacy eTemplate structures (<row>) into datagrid
renderable markup. Common legacy patterns continue to work.
From Slotted Templates
Slotted row template comes from slot="row".
- Preferred wrapper:
<tr slot="row"> - Legacy wrapper:
<row slot="row"> - Any other wrapper is preserved as-is (for example
<sl-card slot="row">)
If the wrapper is <tr> or <row>, bare child widgets are allowed and
are auto-wrapped into <td> cells.
Example:
<tr class="$class $cat_id" slot="row">
<et2-description id="n_family" noLang="1"></et2-description>
<et2-textarea id="note" readonly="true" noLang="1"></et2-textarea>
<et2-vbox>
<et2-url-phone id="tel_work"
readonly="true" class="telNumbers" statustext="Business phone"
></et2-url-phone>
<et2-url-phone id="tel_cell"
readonly="true" class="telNumbers" statustext="Mobile phone"
></et2-url-phone>
<et2-url-phone id="tel_home"
readonly="true" class="telNumbers" statustext="Home phone"
></et2-url-phone>
</et2-vbox>
</tr>
State Templates
Et2Datagrid has two optional state templates:
slot="loader"— placeholder content while rows are loading.slot="noResults"— content shown when loading is complete and no rows are available.
These can be supplied in either a named .xet template parsed by Et2RowProvider or
as live slotted children of the owner component.
State template precedence is:
-
Named-template state content extracted into
templateData.loaderTemplateortemplateData.noResultsTemplate. -
Live slotted content forwarded by the owner component, for example
<slot name="noResults" slot="noResults"></slot>. - The datagrid’s built-in default state UI.
The named .xet template is the app-level definition and is preferred when present. Live slots
are the lower-level component API for owners that do not provide state content through
templateData. The built-in default is only the final fallback.
Any wrapper can be used for state template content.
Example:
<tr slot="loader">
<td colspan="2">
<sl-skeleton effect="sheen" style="width:100%"></sl-skeleton>
</td>
</tr>
<div slot="noResults" class="mail-empty-placeholder">
This mailbox is empty
</div>
Styling row contents
Rows are rendered inside the et2-datagrid shadow DOM. Normal page CSS does not reach row
contents unless the target is exposed as a CSS part.
Preferred row-template styling uses et2-styles inside the row template definition.
Et2RowProvider extracts those styles and passes them into the datagrid row shadow DOM. The
et2-styles element can be placed anywhere inside the row template definition; it does not need
to be inside the <row> element.
<template id="app.index.rows">
<grid>
<columns>
<column id="title"></column>
</columns>
<row>
<et2-description class="entry-title" id="title" noLang="1"></et2-description>
</row>
</grid>
<et2-styles src="row.css"></et2-styles>
</template>
src="row.css" resolves relative to the .xet file containing the row template.
Inline CSS inside et2-styles is also supported.
If the row template contains et2-styles, et2-nextmatch does not load the
application’s templates/default/app.css into the datagrid row shadow DOM. If no row-local
et2-styles is present, app.css is still loaded as the compatibility fallback.
Static Widget Style
For a simple static change that applies to every row, add a class to the row template and style it in the row template stylesheet.
<row>
<et2-description class="entry-title" id="title" noLang="1"></et2-description>
<et2-description id="owner" noLang="1"></et2-description>
</row>
.entry-title {
color: var(--sl-color-primary-700);
font-weight: var(--sl-font-weight-semibold);
}
Static Widget Internals
To style a widget’s exposed internal part from the stylesheet, use ::part() on the widget in
the row template.
<row>
<et2-image class="status" label="Open"></et2-image>
</row>
.status::part(base) {
min-width: 0;
padding-inline: var(--sl-spacing-small);
}
Static Exported Parts
Use exportparts when normal application CSS outside the datagrid needs to style a row widget’s
internal part. The datagrid gathers row-template exportparts and forwards them through
et2-nextmatch.
<row>
<et2-hbox class="contact-methods" exportparts="base:contact-methods__base">
<et2-url-phone id="tel_work" readonly="true"></et2-url-phone>
<et2-url-phone id="tel_cell" readonly="true"></et2-url-phone>
<et2-url-email id="email" readonly="true"></et2-url-email>
</et2-hbox>
</row>
et2-nextmatch::part(contact-methods__base) {
flex-wrap: wrap;
align-content: flex-start;
row-gap: var(--sl-spacing-2x-small);
}
Dynamic Row Class
For dynamic row state, put a class expression on the row or widget and style it in the stylesheet. This is
the most direct option when the server already supplies a class such as overdue,
readonly, or cat_<ID>.
<row class="$class priority_$priority">
<et2-description class="entry-title" id="title" noLang="1"></et2-description>
<et2-description class="entry-status" id="status" noLang="1"></et2-description>
</row>
tr.overdue .entry-status {
color: var(--sl-color-danger-700);
font-weight: var(--sl-font-weight-semibold);
}
tr.priority_high .entry-title {
border-inline-start: 3px solid var(--warning-color);
padding-inline-start: var(--sl-spacing-x-small);
}
Dynamic Widget Class
When only one widget needs dynamic styling, you can put the class expression on that widget instead of the whole row.
<row>
<et2-description class="entry-status status_$status_class" id="status" noLang="1"></et2-description>
</row>
.entry-status.status_warning {
color: var(--sl-color-warning-700);
}
.entry-status.status_error {
color: var(--sl-color-danger-700);
}
Dynamic CSS Property
When an owner widget needs to change the same row styling for all rendered rows, set a CSS custom property on the datagrid or owner widget and use it from the row stylesheet. This keeps row DOM updates out of application code and lets the browser apply the change to currently rendered and newly virtualized rows.
this.datagrid.style.setProperty("--app-row-details-display", showDetails ? "block" : "none");
<row>
<et2-description class="entry-title" id="title" noLang="1"></et2-description>
<et2-description class="entry-details" id="details" noLang="1"></et2-description>
</row>
.entry-details {
display: var(--app-row-details-display, none);
}
Built-in row sizing properties
Et2Datagrid exposes row sizing CSS custom properties for owner widgets and apps that need to
tune standard row layout:
| Property | Default | Effect |
|---|---|---|
--row-height |
3em |
Estimated row height used for virtual spacer rendering and empty rows. |
--row-cell-max-height |
10em |
Maximum height for normal row cells before vertical scrolling. |
Use --row-cell-max-height when row content is being clipped or scrolls too early. It applies to
normal row td / th cells; expanded rows and tile view use separate sizing paths.
et2-nextmatch {
--row-cell-max-height: 16em;
}
Lifecycle (class internals)
The datagrid coordinates Lit’s reactive lifecycle, the @lit-labs/virtualizer, a debounced
request queue, and a deferred row-upgrade pass. This section follows a row from initial setup to a hydrated,
interactive DOM node.
Construction
constructor() (Et2Datagrid.ts:490) is intentionally light: it measures the browser scrollbar width once and binds stable method references
so listeners and the virtualizer can add/remove them cleanly. No DOM or data work happens here. The default
properties (columns, dataProvider, pageSize,
selectionMode, and the private _columnManager /
_columnState instances) are set by the property decorators above.
First paint
firstUpdated() (Et2Datagrid.ts:542) runs once after the first render. It:
- attaches the passive scroll listener (
_maybePrefetchOnScroll) to the scroll body, -
installs the
MutationObserverrow-upgrade watcher via_initRowUpgradeObserver(), - sets up column-resize
interacthandlers.
Structural change detection
willUpdate() (Et2Datagrid.ts:556) runs before each render whenever a reactive property changed. For structure-defining inputs —
templateData, view, rowIdField, columns,
columnPreferenceName, noColumnPersistence, noVisibleHeader — it:
-
invalidates the loaded column-preference key so
_loadColumnPreferencesIfNeeded()re-reads persisted column state, -
captures
_sourceColumnKeysfromtemplateData.sourceColumns(used to remap cells after column reordering), - rebuilds the visible header node set via
_prepareVisibleHeaders(), -
marks
_postRenderStructureSyncNeededsoupdated()can reapply column sizes/visibility, - clears the row-upgrade queue and resets virtualizer caches when the structure changed.
When columns change it also rebuilds the cached customfield column state
(_rebuildCustomfieldColumnStateCache()), which row hydration reads to avoid per-row header
scans.
updated() (Et2Datagrid.ts:618) performs the post-render structure sync (column sizes, visibility), re-adopts
rowStylesheets, re-runs the row-upgrade observer/scan, and restores focus to the active row
after a render if needed.
Data-load trigger
There are two ways rows start loading:
-
Owner-driven —
loadMore()(Et2Datagrid.ts:4197) andreload()(Et2Datagrid.ts:3982) request from index0.reload()wipes all loaded rows (_clearRows()), resetstotal, and re-fetches. These are the public entry points an owner widget calls. -
Virtualizer-driven — when the virtualizer renders an index that has no loaded row,
_renderVirtualRow()(Et2Datagrid.ts:1835) emits a placeholder and calls_requestChunkForRowIndex()(Et2Datagrid.ts:1934). This is how infinite-scroll paging and scroll-into-view prefetch happen.scrollevents also re-arm queued-request processing via_maybePrefetchOnScroll().
Both paths funnel into the same debounced queue.
Fetch
The request queue coalesces bursts (fast scrolling) and dedupes by a deterministic key built from start,
count, and provider query signature (_requestKey()):
_queueRequest() (Et2Datagrid.ts:1205) records the request and bumps _pendingPlaceholderCount (embedded grids reserve a single
loading row).
_scheduleQueuedRequestProcessing() (Et2Datagrid.ts:1219) debounces (default 100 ms).
_processQueuedRequests() (Et2Datagrid.ts:1349) marks the request in-flight, sets loading / fetching, dispatches
et2-loading-start, and calls _fetchPage().
_fetchPage() (Et2Datagrid.ts:1243) awaits dataProvider.fetchPage(start, count) and:
- sets
fetchFailed/fetchErrorMessageand_hasFetchedOnce, - writes
this.totalfrom the response when present, -
merges rows into
_rowsByIndex[index], deduplicating viadisplayedRowIds, then rebuilds the flatthis.rowsarray, -
in
finally, decrements placeholders, removes the in-flight key, fireset2-loading-doneoret2-loading-error, and calls_reconcileRowRenderState().
_reconcileRowRenderState() (Et2Datagrid.ts:1394) prunes expanded rows that became non-expandable after refresh and, when
autoActivateFirstRow is set and no active row exists, pins activeRowIndex = 0 so
keyboard navigation works as soon as the first row appears.
loading, fetching, and total are @state() so the
relevant templates re-render. The _stateTemplate() (Et2Datagrid.ts:4250) resolves the high-level visual state — initial loading, fetch error, missing template, or empty — and
renders the loader, error, or no-results UI accordingly.
Row generation
render() (Et2Datagrid.ts:4444) is the heart of presentation. For each render it:
-
computes
visibleColumnsand resolves CSS custom properties (--column-sizes,--column-count,--scrollbar-space,--embedded-virtualized-height), -
computes
rowCount = _virtualRowCount()(Et2Datagrid.ts:2022), which istotalwhen known or the materialized count otherwise, -
builds the virtualizer
itemsvia_getVirtualItems()(Et2Datagrid.ts:1982) — inserting anexpandeditem immediately after each expanded parent, -
passes a stable
keyFunction(_virtualRowKey, Et2Datagrid.ts:2062) and therenderItemcallback (_renderVirtualRow) tovirtualize().
_renderVirtualRow() (Et2Datagrid.ts:1835) is invoked by the virtualizer for every visible slot:
-
if the row exists in
_rowsByIndex, it calls_buildRowElement()and serializes the result withunsafeHTML(rows are stamped as fast, inert DOM strings for throughput), - otherwise it renders a placeholder (skeleton or the slot loader) and triggers a chunk request.
_buildRowElement() (Et2Datagrid.ts:1544) is where a logical row becomes a DOM node:
-
It clones the prepared
<template>(document.importNode(template.content, true)) — or falls back to a simple<tr>built from column values when no template exists. -
_populateCloneWithRow()(Et2Datagrid.ts:2401) walks text nodes and resolves direct and legacy row placeholders viaEt2RowProvider.resolveSimpleRowPlaceholders(). -
_populateRowRootAttributes()(Et2Datagrid.ts:2423) resolves root-level placeholder attributes (e.g. dynamic row classes) viaEt2RowProvider.customizeRowRootAttributes(). -
_markRowElement()(Et2Datagrid.ts:2116) stamps accessibility/identity attributes:role,data-row-id,data-row-index,aria-rowindex,aria-selected, andtabindex. -
_ensureMetaCell()(Et2Datagrid.ts:1602) ensures the leading metadata cell exists and wires the row expander when the row is expandable; it also invokesrowCustomizer(see Customization points). -
The node is tagged with the
loadingclass and_applyColumnLayoutToRowElement()applies column track sizing.
Hydration (deferred row binding)
Row templates are stamped as inert strings, so widget binding is deferred to keep scrolling/rendering
responsive. Direct row bindings are resolved from the current rowData during that deferred
pass; an ArrayMgr perspective is only a compatibility fallback.
_initRowUpgradeObserver() (Et2Datagrid.ts:1755) installs a MutationObserver on the scroll body that calls
_upgradeRenderedRows() whenever rows are added/moved.
_upgradeRenderedRows() (Et2Datagrid.ts:2211) finds newly realized physical rows, skips already-upgraded nodes for the same row identity, and enqueues
them.
_processRowUpgradeQueue() (Et2Datagrid.ts:2326) processes a bounded batch per animation frame (≤ 8 rows, 8 ms budget) so input/paint stay smooth. For
each row it calls _applyRowElementAttributes().
_applyRowElementAttributes() (Et2Datagrid.ts:2436) is the hydration core. It:
- reads
rowTemplateAttrMapfor each element carryingdata-et2nm-id, -
resolves direct and normalized legacy row expressions from
rowDatabefore widget transformation, - supplies direct
idbindings as widget values when the widget supports values, - uses the normal content manager for non-row expressions and opens a row-scoped ArrayMgr perspective only when direct resolution cannot safely handle an expression,
-
for
et2-customfields-listelements, applies cached customfield state via_applyCustomfieldRowState(), - for the row root, applies stored root attributes,
-
for other widgets, calls
transformAttributes(stored)(or falls back tosetAttributewithmgr.expandName()), - re-runs the row customizer and finally removes the
loadingclass.
Because the virtualizer can materialize rows after updated(),
_scheduleRenderedRowsUpgradeScan() (Et2Datagrid.ts:2249) re-scans for up to ~30 frames to catch late handoff.
Refresh and reload
refresh(row_ids, type) (Et2Datagrid.ts:4001) applies a targeted refresh without a full reload. For DELETE it removes rows client-side (
_removeRowsById,
Et2Datagrid.ts:4121); otherwise it awaits dataProvider.refresh() and merges results via
_applyRefreshedRows() (Et2Datagrid.ts:4048), which swaps row data in place, bumps a render version (triggering a re-render of that row via the
virtual key), and pulses the changed rows for visual feedback.
reload() (Et2Datagrid.ts:3982) wipes loaded state and re-fetches from index 0.
Rendering pipeline (summary)
Row rendering is split into preparation and per-row hydration:
-
Et2RowProviderfinds the row template, normalizes it, extracts columns, and compiles it into a reusable template. Row-independent values are resolved at this stage, including static$cont/@...expressions and literal strings. -
Et2RowProviderrecords row-scoped widget attributes in the template attribute map instead of permanently resolving them on the reusable template. Et2Datagridclones the prepared row template for each row needed by the virtualizer.-
Et2Datagridapplies recorded row-scoped widget attributes to the clone using that row’srowData, which came from the configuredEt2DatagridDataProvider.
This order keeps static template work shared across all rows while preserving correct row-specific values for each physical row clone. The virtualizer determines which row indexes need DOM nodes and manages their addition and removal; the data provider supplies row objects, and the prepared template controls how each row object becomes DOM.
Key methods
Visibility legend: public (called by owner widgets), private (internal only).
| Method | Visibility | Stage | Purpose |
|---|---|---|---|
loadMore() |
public | load | Request the first (or next missing) page from index 0. |
reload() |
public | load | Clear all rows and re-fetch; reset total and error state. |
setInitialRows(rows) |
public | load |
Seed preloaded row data (skips the initial provider fetch) and fire et2-loading-done.
|
refresh(row_ids, type) |
public | refresh | Targeted in-place refresh or removal without a full reload. |
selectSingleRow(rowId) |
public | selection | Select one loaded row and emit et2-selection-changed. |
selectAllRows() |
public | selection | Select all currently loaded rows when selectionMode is multiple. |
clearSelection() |
public | selection | Clear selected rows and optionally emit the selection event. |
focusFirstRow() |
public | focus | Move active focus to the first loaded row. |
focusRowById(rowId) |
public | focus | Move active focus to a loaded row by id. |
clearActiveRow() |
public | focus | Clear active-row focus state. |
openColumnSelection(event?) |
public | columns | Open the column chooser from an owner-level control. |
render() |
Lit | render | Builds the virtualizer config, headers, state template, and CSS vars. |
_getVirtualItems() |
private | render | Builds virtualizer item list, inserting expanded items after parents. |
_virtualRowCount() |
private | render | Resolves slot count (total vs materialized count). |
_virtualRowKey() |
private | render | Stable key per row/expanded/placeholder; includes structure + render version. |
_renderVirtualRow() |
private | generate | Per-slot callback: build row DOM or emit placeholder + chunk request. |
_requestChunkForRowIndex() |
private | generate | Queue a page fetch for the chunk owning an unloaded index. |
_buildRowElement() |
private | generate | Clone template, resolve placeholders, mark, ensure meta cell, layout. |
_populateCloneWithRow() |
private | generate | Resolve direct and legacy row text placeholders in the cloned fragment. |
_populateRowRootAttributes() |
private | generate | Resolve placeholder attributes on the row root. |
_markRowElement() |
private | generate |
Stamp a11y/identity attributes (role, data-row-*, aria-*,
tabindex).
|
_ensureMetaCell() |
private | generate | Ensure leading metadata cell + expander; invoke rowCustomizer. |
_applyColumnLayoutToRowElement() |
private | generate | Apply column track sizing to the row. |
_initRowUpgradeObserver() |
private | hydrate | MutationObserver that enqueues realized rows for hydration. |
_upgradeRenderedRows() |
private | hydrate | Find newly realized rows, skip upgraded, enqueue. |
_processRowUpgradeQueue() |
private | hydrate | Bounded per-frame hydration: bind widgets, customfields, customizer. |
_applyRowElementAttributes() |
private | hydrate | Apply row attrs directly; use an ArrayMgr perspective only as fallback. |
_scheduleRenderedRowsUpgradeScan() |
private | hydrate | Re-scan frames to catch virtualizer-late rows. |
_queueRequest() |
private | fetch | Record a debounced request + placeholder count. |
_processQueuedRequests() |
private | fetch | Dispatch queued requests, fire et2-loading-start. |
_fetchPage() |
private | fetch | Await dataProvider.fetchPage(), merge rows, fire done/error. |
_reconcileRowRenderState() |
private | fetch | Prune stale expansions, pin first active row, request render. |
_stateTemplate() |
private | state | Resolve loading/error/missing-template/empty UI. |
_applyRefreshedRows() |
private | refresh | Merge provider refresh result; pulse changed rows. |
_removeRowsById() |
private | refresh | Remove rows client-side; fix counts/selection. |
Customization points and overrides
rowCustomizer
rowCustomizer is a Et2DatagridRowCustomizer callback invoked for every realized
row, both during row generation (_ensureMetaCell) and again after hydration
(_rerunRowCustomizer,
Et2Datagrid.ts:2530). Use it for presentation tweaks that depend on row data — badges, meta-cell indicators, or DOM
adjustments the row template cannot express.
import type {Et2DatagridRowCustomizer} from "./Et2Datagrid.types";
const rowCustomizer : Et2DatagridRowCustomizer = ({rowElement, rowData, rowIndex, metaCell}) =>
{
// Add a per-row indicator into the leading metadata cell.
if(rowData.overdue)
{
metaCell.classList.add("row-overdue");
}
// Toggle a class on the whole row based on data.
rowElement.classList.toggle("row-priority-high", rowData.priority === "high");
};
this.datagrid.rowCustomizer = rowCustomizer;
The context is { rowElement, rowData, rowIndex, metaCell }. metaCell is the
leading column-0 cell (td[data-dg-meta-cell="1"] in row view,
[data-dg-meta-cell="1"] in tile view).
expansionConfig (expandable rows)
Et2DatagridExpansionConfig owns the content of expandable rows; the datagrid owns the
expander mechanics and column alignment. The contract is intentionally free of Nextmatch-specific hierarchy
— Nextmatch maps its parent_id / is_parent fields into these hooks.
| Hook | Purpose |
|---|---|
isExpandable(row, rowIndex) |
Return true for rows that should render an expander. |
renderExpandedContent(context) |
Render detail content immediately after the parent row. Can return another
et2-datagrid.
|
expandedRowIds? |
Optional controlled set of expanded row ids. |
onExpandedRowIdsChanged? |
Called with the next expanded-id set when expansion toggles. |
emptyTemplate? |
Optional empty-state renderer for custom detail UI. |
import {Et2Datagrid} from "./Et2Datagrid";
import type {Et2DatagridExpansionConfig} from "./Et2Datagrid.types";
const expansionConfig : Et2DatagridExpansionConfig = {
// Expand only parent rows (Nextmatch hierarchy contract).
isExpandable: (row) => !!row.data.is_parent,
renderExpandedContent: ({row, parentGrid}) =>
{
// Return another datagrid as the child detail view.
const parent = parentGrid as Et2Datagrid;
const child = document.createElement("et2-datagrid") as Et2Datagrid;
child.dataProvider = new ChildProvider(row.data.id);
child.columns = parent.columns;
child.templateData = parent.templateData;
child.embeddedVirtualized = true; // no own scrollport; parent scrolls
child.noColumnPersistence = true; // columns owned by parent
return child;
},
// Controlled expansion state (optional).
expandedRowIds: new Set<string>(),
onExpandedRowIdsChanged: (next) =>
{
// Persist or reflect expansion state in the owner widget.
},
};
this.datagrid.expansionConfig = expansionConfig;
The expanded content receives Et2DatagridExpandedRowContext (row,
rowIndex, parentGrid, columnSizes, metaColumnWidth) so
it can align itself to the parent column tracks.
dataProvider override
Subclass or implement Et2DatagridDataProvider to supply rows from any source. A minimal custom
provider:
import type {
Et2DatagridDataProvider,
Et2DatagridPageResult,
Et2DatagridRefreshResult,
Et2DatagridUpdateType
} from "./Et2Datagrid.types";
class MyProvider implements Et2DatagridDataProvider
{
async fetchPage(start : number, pageSize : number) : Promise<Et2DatagridPageResult>
{
const page = await myApi.getRows(start, pageSize);
return {
rows: page.rows.map(r => ({id: this.normalizeRowId(r.id, true), data: r})),
total: page.total
};
}
async refresh(row_ids : string[], _type : Et2DatagridUpdateType) : Promise<Et2DatagridRefreshResult>
{
const providerIds = row_ids.map(id => this.toProviderRowId(this.normalizeRowId(id, true)));
const rows = await myApi.getRowsById(providerIds);
return {
rows: rows.map(r => ({id: this.normalizeRowId(r.id, true), data: r})),
removedRowIds: []
};
}
// Datastore ids may carry a type prefix (e.g. "calendar::123"). Keep them stable.
normalizeRowId(rowId : string | number, ensurePrefix = false) : string
{
const id = String(rowId);
return ensurePrefix && !id.includes("::") ? `myapp::${id}` : id;
}
toProviderRowId(dataStoreRowId : string) : string
{
return dataStoreRowId.replace(/^myapp::/, "");
}
// Optional: lets the grid skip refetching when the query is unchanged.
getQuerySignature() : string
{
return myApi.currentQuerySignature();
}
}
this.datagrid.dataProvider = new MyProvider();
getQuerySignature() should change whenever the underlying query (filters, sort) changes, so the
request-dedup key (_requestKey) and virtual keys invalidate stale rows.
getDataStorePrefix() is used by nested/child grids to namespace row ids.
Row-scoped deferred attributes (rowTemplateAttrMap)
Row templates may carry attributes that depend on the row, such as
class="$class priority_$priority". Et2RowProvider does
not permanently resolve these on the shared template; instead it records them in
templateData.rowTemplateAttrMap keyed by the generated widget id (data-et2nm-id).
During hydration, _applyRowElementAttributes() resolves direct row bindings against the current
rowData so each physical clone gets its own concrete values. Unsupported expressions retain the
ArrayMgr perspective fallback.
As an app author you normally do not populate rowTemplateAttrMap directly — you write the
expression in the template and let Et2RowProvider record it. The mechanism matters when you
build custom row templates or providers and need row-specific widget attributes that cannot be expressed as
static template text.
Column hide expressions and headers
Column metadata (Et2DatagridColumn) may carry a disabled flag (fixed
hidden/unavailable in the chooser) and a hidden flag (currently hidden but user-toggleable).
Headers are live elements (column.header) and may expose methods such as
getCustomfieldVisibility() — used by the datagrid to cache customfield state per column
(_rebuildCustomfieldColumnStateCache). Column hide/show expressions are evaluated by
_parseColumnBooleanExpression() (Et2Datagrid.ts:2709) against the content array manager. Custom column widgets can therefore drive visibility and sizing
through their own header element.
Child-grid and layout flags
| Property | Effect |
|---|---|
inheritColumnSizes |
Let --column-sizes inherit from the host (child grids whose tracks are owned by a
parent).
|
noColumnPersistence |
Disable loading/saving column preferences (child grids). |
noColumnResize |
Disable interactive column resizing owned by another component. |
noVisibleHeader |
Hide only the visible header row; <thead> still renders for a11y/sizing. |
autoHeight |
Grow to fit rows instead of creating an own scroll body (expanded children). |
embeddedVirtualized |
Embedded virtualized grid inside an ancestor scrollport — keeps lazy paging but no own scrollport. |
autoActivateFirstRow |
Mark the first loaded row active (subgrids disable this). |
view = "tile" |
Non-row wrapping virtualized layout; every entry remains its own item. |
Slots
| Name | Description |
|---|---|
header
|
Header content used when no column definitions are available. |
noResults
|
Optional empty-state content shown when there are no rows. |
expand-icon
|
Optional icon shown for collapsed expandable rows. |
collapse-icon
|
Optional icon shown for expanded rows. |
Learn more about using slots.
Properties
| Name | Description | Reflects | Type | Default |
|---|---|---|---|---|
accesskey
|
Accesskey provides a hint for generating a keyboard shortcut for the current element. The attribute value must consist of a single printable character. |
|
string
|
- |
actions
|
Set Actions on the widget Each action is defined as an object: move: { type: “drop”, acceptedTypes: “mail”, icon: “move”, caption: “Move to” onExecute: javascript:mail_move” } This will turn the widget into a drop target for “mail” drag types. When “mail” drag types are dropped, the global function mail_move(egwAction action, egwActionObject sender) will be called. The ID of the dragged “mail” will be in sender.id, some information about the sender will be in sender.context. The etemplate2 widget involved can typically be found in action.parent.data.widget, so your handler can operate in the widget context easily. The location varies depending on your action though. It might be action.parent.parent.data.widget To customise how the actions are handled for a particular widget, override _link_actions(). It handles the more widget-specific parts. |
object
|
- | |
align
|
Used by Et2Box to determine alignment. Allowed values are left, right |
|
string
|
- |
autoActivateFirstRow
|
Automatically mark the first loaded row active. Subgrids disable this so simply expanding a row does not create multiple active rows. |
boolean
|
true
|
|
autoHeight
auto-height
|
Let the grid grow to fit its rows instead of creating its own scroll body. Used for expanded child grids so the parent grid remains the only vertical scroller. |
|
boolean
|
false
|
class
|
CSS Class. This class is applied to the outside, on the web component itself. Due to how WebComponents work, this might not change anything inside the component. |
|
string
|
- |
columnPreferenceName
column-preference-name
|
Optional explicit preference key for persisted column state. When omitted, datagrid derives key from owner component + row template id. |
string
|
""
|
|
columns
|
Visible column configuration, including sizing and optional hide expressions. |
Et2DatagridColumn[]
|
[]
|
|
configurationLoading
configuration-loading
|
External loading flag for configuration/template setup before first data render. |
boolean
|
false
|
|
data
|
Set the dataset from a CSV |
string
|
- | |
dataProvider
|
Paging adapter used by infinite scroll to fetch additional rows from the server. |
Et2DatagridDataProvider | null
|
null
|
|
deferredProperties
|
Any attribute that refers to row content cannot be resolved immediately, but some like booleans cannot stay a string because it’s a boolean attribute. We store them for later, and parse when they’re fully in their row. If you are creating a widget that can go in a nextmatch row, and it has boolean attributes that can change for each row, add those attributes into deferredProperties | - | - | |
disabled
|
Defines whether this widget is visibly disabled. The widget is still visible, but clearly cannot be interacted with. Widgets disabled in the template will not return a value to the application code, even if re-enabled via javascript before submitting. To allow a disabled widget to be re-enabled and return a value, disable via javascript in the app’s et2_ready() instead of an attribute in the template file. |
|
boolean
|
false
|
dom_id
|
Get the actual DOM ID, which has been prefixed to make sure it’s unique. |
string
|
- | |
embeddedVirtualized
embedded-virtualized
|
Render as an embedded virtualized grid inside an ancestor scrollport. Unlike simple auto-height, this mode keeps lazy paging but does not create an independent scrollport. It starts with one loading row, then keeps the host, root CSS variable, and virtualizer body height synchronized to the larger of the virtualizer estimate and the actual rendered row stack. |
|
boolean
|
false
|
emptyStateActionMenu
empty-state-action-menu
|
Show an empty-state action menu button. The button dispatches a composed contextmenu event from the empty row so owners can use their normal row action-menu routing. |
boolean
|
false
|
|
emptyStateText
empty-state-text
|
Optional replacement for the default empty-state headline text. Keeps default empty-state template structure while allowing Nextmatch-level customization. |
string
|
""
|
|
expansionConfig
|
Optional generic expanded-row hooks supplied by consumers such as Et2Nextmatch. |
Et2DatagridExpansionConfig | null
|
null
|
|
fetchErrorMessage
|
Optional provider error message shown in error state. |
string
|
""
|
|
fetchFailed
|
Error state set when the latest fetch failed. |
boolean
|
false
|
|
fetching
|
Guard flag used to prevent overlapping fetchPage() calls. |
boolean
|
false
|
|
hidden
|
The widget is not visible. As far as the user is concerned, the widget does not exist. Widgets hidden with an attribute in the template may not be created in the DOM, and will not return a value. Widgets can be hidden after creation, and they may return a value if hidden this way. |
|
boolean
|
- |
id
|
Get the ID of the widget |
string
|
- | |
inheritColumnSizes
inherit-column-sizes
|
Let --column-sizes inherit from the host instead of computing it from local columns.
Used by child grids whose visual tracks are owned by a parent grid, while local columns still define
cell order/visibility.
|
boolean
|
false
|
|
label
|
The label of the widget This is usually displayed in some way. It’s also important for accessability. This is defined in the parent somewhere, and re-defining it causes labels to disappear |
string
|
- | |
loading
|
True while a fetch cycle is active, including initial and incremental page loads. |
boolean
|
false
|
|
noColumnPersistence
|
Disable loading and saving column preferences. Useful for child grids whose columns are owned by a parent grid. |
boolean
|
false
|
|
noColumnResize
|
Disable interactive column resizing for grids whose column sizing is owned by another component. |
boolean
|
false
|
|
noColumnSelection
|
Hide the column chooser action in the header when true. |
boolean
|
false
|
|
noLang
|
Disable any translations for the widget |
boolean
|
- | |
noVisibleHeader
no-visible-header
|
Hide only the visible header row. The table <thead> remains rendered for
accessibility and sizing semantics.
|
boolean
|
false
|
|
pageSize
|
Maximum number of rows requested per page load. |
number
|
50
|
|
parentId
|
Parent is different than what is specified in the template / hierarchy. Widget ID of another node to insert this node into instead of the normal location |
string
|
- | |
parentRowId
|
Parent row id when this grid is rendered as expanded child content. |
string
|
""
|
|
rowCustomizer
|
Optional hook invoked for each realized row to customize row/meta-cell presentation. |
Et2DatagridRowCustomizer | null
|
null
|
|
rows
|
Rows currently materialized in the DOM/in-memory list. |
Et2DatagridRow[]
|
[]
|
|
selectionMode
selection-mode
|
Row selection behavior: none, single, or multiple. |
Et2DatagridSelectionMode
|
"multiple"
|
|
statustext
|
Tooltip which is shown for this element on hover |
|
string
|
- |
styles
|
WebComponent * | - | - | |
templateData
|
Prepared template and metadata used to render each row. |
Et2DatagridTemplateData | null
|
null
|
|
total
|
Total row count reported by provider, or null when unknown. |
number | null
|
null
|
|
view
|
Visual layout mode. Row is the default table layout. |
|
Et2DatagridView
|
"row"
|
options
|
Get property-values as object
use widget methods |
object
|
- | |
supportedWidgetClasses
|
et2_widget compatability
Legacy compatability. Some legacy widgets check their parent to see whats allowed |
array
|
[]
|
|
updateComplete |
A read-only promise that resolves when the component has finished updating. |
Learn more about attributes and properties.
Events
| Name | React Event | Description | Event Detail |
|---|---|---|---|
et2-columns-changed |
Fired when column order, width, or visibility changes. |
CustomEvent
|
|
et2-loading-error |
Fired when a row fetch request fails. |
CustomEvent
|
|
et2-loading-done |
Fired when row data is ready: after all in-flight fetches complete, or after setInitialRows() seeds preloaded rows. |
CustomEvent
|
|
et2-loading-start |
Fired when one or more row fetch requests are dispatched. |
CustomEvent
|
|
et2-datagrid-leave-child-grid |
EVENT NEEDS A DESCRIPTION |
CustomEvent
|
|
et2-datagrid-enter-expanded-row |
EVENT NEEDS A DESCRIPTION |
CustomEvent
|
|
et2-column-selection-items |
EVENT NEEDS A DESCRIPTION |
CustomEvent
|
|
et2-column-selection-apply |
EVENT NEEDS A DESCRIPTION |
CustomEvent
|
|
et2-active-row-changed |
Fired when keyboard or pointer navigation changes the active row. |
CustomEvent
|
|
et2-selection-changed |
Fired when row selection changes. |
CustomEvent
|
Learn more about events.
Methods
| Name | Description | Arguments |
|---|---|---|
checkCreateNamespace()
|
Checks whether a namespace exists for this element in the content array. If yes, an own perspective of the content array is created. If not, the parent content manager is used. Constructor attributes are passed in case a child needs to make decisions | - |
clear()
|
Reset all grid runtime state including selection and fetch markers. | - |
clone()
|
Creates a copy of this widget. |
_parent: et2_widget
|
createElementFromNode()
|
Create a et2_widget from an XML node. First the type and attributes are read from the node. Then the readonly & modifications arrays are checked for changes specific to the loaded data. Then the appropriate constructor is called. After the constructor returns, the widget has a chance to further initialize itself from the XML node when the widget’s loadFromXML() method is called with the node. |
_node: , _name:
|
getArrayMgr()
|
Returns the array manager object for the given part |
managed_array_type: string
|
getArrayMgrs()
|
Returns an associative array containing the top-most array managers. |
_mgrs: object
|
getChildren()
|
Get child widgets Use |
- |
getInstanceManager()
|
Returns the instance manager | - |
getPath()
|
Returns the path into the data array. By default, array manager takes care of this, but some extensions need to override this | - |
getRoot()
|
Returns the base widget Usually this is the same as getInstanceManager().widgetContainer | - |
loadFromXML()
|
Loads the widget tree from an XML node |
_node:
|
loadingFinished()
|
Needed for legacy compatability. |
promises: Promise[]
|
loadMore()
|
Trigger next page load when allowed by current state. | - |
openColumnSelection()
|
Open the column selection dialog. This is public so containers can expose the same column chooser outside the datagrid header. |
event: Event
|
parseXMLAttrs()
|
The parseXMLAttrs function takes an XML DOM attributes object and adds the given attributes to the _target associative array. This function also parses the legacyOptions. N.B. This is only used for legacy widgets. WebComponents use transformAttributes() and do their own handling of attributes. |
_attrsObj: , _target: object, _proto: et2_widget
|
refresh()
|
Apply a targeted row refresh without forcing a full grid reload. The provider decides which rows changed or disappeared; the datagrid only updates rows it already has materialized locally. |
row_ids: string[], type: Et2DatagridUpdateType
|
reload()
|
Clear current rows and load from first page. | - |
selectSingleRow()
|
Select exactly one row by id and synchronize visual/accessibility state. |
rowId: string
|
set_label()
|
NOT the setter, since we cannot add to the DOM before connectedCallback() TODO: This is not best practice. Should just set property, DOM modification should be done in render https://lit-element.polymer-project.org/guide/templates#design-a-performant-template |
value: string
|
setArrayMgr()
|
Sets the array manager for the given part |
_part: string, _mgr: object
|
setArrayMgrs()
|
Sets all array manager objects - this function can be used to set the root array managers of the container object. |
_mgrs: object
|
setInitialRows()
|
Seed datagrid with preloaded rows and skip initial fetch. |
rows: any[]
|
setInstanceManager()
|
Set the instance manager Normally this is not needed as it’s set on the top-level container, and we just return that reference |
manager: etemplate2
|
_get_action_links()
|
Get all action-links / id’s of 1.-level actions from a given action object This can be overwritten to not allow all actions, by not returning them here. |
actions:
|
_handleClick()
|
Click handler calling custom handler set via onclick attribute to this.onclick |
_ev: MouseEvent
|
_handleColumnSelectionClick()
|
Handle column selection action from the header button. |
event: MouseEvent
|
_headerTemplate()
|
Render the visible column header row (or fallback header slot). |
visibleColumns: Et2DatagridColumn[]
|
_link_actions()
|
Link the actions to the DOM nodes / widget bits. |
actions: object
|
_set_label()
|
Do some fancy stuff on the label, splitting it up if there’s a %s in it Normally called from updated(), the “normal” setter stuff has already been run before this is called. We only override our special cases (%s) because the normal label has been set by the parent |
value: string
|
destroy()
|
et2_widget compatability
true |
- |
set_class()
|
Set the widget class
Use this.class or this.classList instead |
new_class: string
|
set_disabled()
|
Wrapper on this.disabled because legacy had it.
Use widget.disabled for visually disabled, widget.hidden for visually hidden. Disabled vs Readonly vs Hidden |
value: boolean
|
set_statustext()
|
supports legacy set_statustext
use this.statustext |
value: string
|
Learn more about methods.
Custom Properties
| Name | Description | Default |
|---|---|---|
--row-height |
Estimated row height used for spacer rendering. | 3em |
--row-cell-max-height |
Maximum height for individual row cells before vertical scrolling. | 10em |
--meta-column-width |
Width of leading metadata column; expandable grids default it wide enough for the expander. | 0px |
--row-expander-size |
Width and height of the row expand/collapse button. | 20px |
--row-expander-icon-size |
Size of the default CSS triangle expander icon. | 6px |
--column-sizes |
Grid-template column track definition used by header/body rows. | |
--column-count |
Column count fallback when explicit track sizes are not set. | 1 |
--scrollbar-space |
Reserved right-side space in header for body scrollbar alignment. | 0px |
--column-selection-width |
Width of the header column selection action. | 16px |
--embedded-virtualized-height |
Synced reserved height for an embedded virtualized grid with no own scrollbar. |
Learn more about customizing CSS custom properties.
Parts
| Name | Description |
|---|---|
base |
Root wrapper around the grid header and body. |
header |
Visible column header row container. |
body |
Scrollable container for state content and table. |
state |
State message container (loading, empty, template missing, or fetch error). |
state-action-menu |
Empty-state action menu button. |
resize-helper |
Helper bar shown while resizing a column. |
table |
Internal table element with ARIA grid semantics. |
rows |
Table body that hosts virtualized row content. |
meta-column |
Leading header column used for row metadata indicators. |
row-meta |
Leading per-row metadata cell (column 0), customizable by consumers. |
row-expander |
Expand/collapse button rendered in the row metadata cell. |
row-expander-icon |
Icon wrapper inside the row expander button. |
expanded-row |
Cell containing consumer-provided expanded row content. |
column |
A visible header column wrapper. |
column-selection |
Column selection action container in the header. |
Learn more about customizing CSS parts.