Questa pagina è stata tradotta automaticamente e può contenere errori. Leggi l'originale in inglese

Elementi

DataTable

DataTable mostra righe e colonne come un foglio di calcolo e scorre in entrambe le direzioni su un numero qualsiasi di esse. Solo le celle in vista vengono create, perciò una tabella di un milione di righe e diecimila colonne scorre come una piccola. Righe, colonne o celle si selezionano con il puntatore e con la tastiera; le colonne hanno larghezze fisse, si ridimensionano trascinandone il bordo, si spostano trascinandone il titolo, restano a sinistra mentre le altre scorrono e si ordinano. I titoli possono stare sotto etichette di gruppo, e una cella o un titolo può essere disegnato dall’app.

el-data-table.tsx
el-data-table.tsxLive
import { mount, signal, Text, View } from "nsh";
import { DataTable, type DataTableColumn, type DataTableSort } from "nsh/base";
import { dataTableClasses, dataTableFitPadding, Log, Segmented, Split, ui, wide } from "./palette";

const NAMES = ["Ada", "Alan", "Grace", "Linus", "Margaret", "Dennis", "Barbara", "Ken"];
const CITIES = ["Oslo", "Lima", "Kyoto", "Cairo", "Perth", "Quito", "Turin", "Hanoi"];

type Person = { id: number; name: string; city: string; score: number };

const people: Person[] = Array.from({ length: 2000 }, (_, i) => ({
  id: i + 1,
  name: `${NAMES[i % NAMES.length]} ${i + 1}`,
  city: CITIES[(i * 7) % CITIES.length],
  score: (i * 37) % 1000,
}));

const columns: DataTableColumn[] = [
  { key: "id", title: "ID", width: 70, align: "end", fixed: true, sortable: true },
  { key: "name", title: "Name", width: 150, sortable: true },
  { key: "city", title: "City", width: 120, sortable: true },
  { key: "score", title: "Score", width: 90, align: "end", sortable: true },
];

// Sorting is the app's: the table reports the next sort (`onSortChange`),
// the app orders its rows and sets `sort`.
function App() {
  const mode = signal<"row" | "cell">("row");
  const sort = signal<DataTableSort | undefined>(undefined);
  const rows = signal<Person[]>(people);
  const events = signal<string[]>([]);
  const log = (line: string) => events.set([line, ...events()].slice(0, 4));

  const sortBy = (next: DataTableSort | undefined) => {
    sort.set(next);
    if (!next) return rows.set(people);
    const key = next.key as keyof Person;
    const sign = next.direction === "descending" ? -1 : 1;
    rows.set([...people].sort((a, b) => (a[key] < b[key] ? -sign : a[key] > b[key] ? sign : 0)));
  };

  return (
    <View style={{ flex: 1, backgroundColor: ui().page, padding: 20, paddingTop: 24, gap: 14 }}>
      <Text style={{ fontSize: 22, fontWeight: "700", color: ui().text }}>data table</Text>
      <Text style={{ color: ui().muted }}>Press a title to sort, drag its edge to resize or the title to move it</Text>

      <Split
        grow
        width={680}
        inspector={
          <>
            <Segmented label="selection" options={["row", "cell"] as const} value={mode()} onChange={(v) => mode.set(v)} />
            <Log title="events" lines={events()} minHeight={96} />
          </>
        }
      >
        <View style={{ height: wide() ? 360 : 320 }}>
          <DataTable
            columns={columns.map((column) => ({ ...column, fitPadding: dataTableFitPadding }))}
            classes={dataTableClasses}
            data={rows()}
            rowHeader={false}
            stripe
            cellSelectable={mode() === "cell"}
            sort={sort()}
            onSortChange={({ sort: next }) => {
              sortBy(next ?? undefined);
              log(`onSortChange: ${next ? `${next.key} ${next.direction}` : "none"}`);
            }}
            onSelectionChange={({ selection }) => log(`onSelectionChange: ${selection ? JSON.stringify(selection) : "none"}`)}
            onColumnResize={({ key, width }) => log(`onColumnResize: ${key} ${Math.round(width)}`)}
            style={{ flex: 1 }}
          />
        </View>
      </Split>
    </View>
  );
}

mount(App);

DataTable fornisce layout, allineamento, virtualizzazione e interazione. L’app dà alle sue parti padding, colori, bordi e feedback di selezione tramite classes e styles. Rust ne crea una con nsh_base::data_table(), TSX con <DataTable> da nsh/base.

use nsh_base::{DataTableColumn, data_table};
use nsh_core::prelude::*;

fn column(key: &str, title: &str) -> DataTableColumn {
    let mut column = DataTableColumn::default();
    column.key = key.into();
    column.title = Some(title.into());
    column
}

fn table() -> impl IntoElement {
    data_table()
        .columns(vec![column("name", "Name"), column("city", "City")])
        .flex_1()
}

La tabella riempie il riquadro che l’app le assegna (flex-1, un’altezza) e scorre al suo interno: in verticale tra le righe e in orizzontale tra le colonne, con barre di scorrimento (scrollbar={false} le nasconde, bounces={false} elimina il rimbalzo alle estremità dove una piattaforma lo prevede).

#Righe e colonne

data sono le righe: oggetti i cui campi sono indicati dai key delle colonne, oppure array che le colonne indicizzano per posizione. Numeri, booleani e stringhe vengono mostrati come testo. Rust fornisce le righe un campo alla volta, ciascuno di un solo tipo: DataTableRows::new(2).texts("symbol", ["AAPL", "MSFT"]).numbers("change", [1.2, -0.4]). Una colonna è un DataTableColumn:

CampoDescrizione
keyChi è, univoco tra le colonne: il campo delle righe che le sue celle mostrano, e il nome usato dagli eventi e dal ref.
titleIl testo del suo titolo. Per default il suo key.
widthLa sua larghezza, in punti. Per default 120.
minWidth, maxWidthLa larghezza minima e massima che un trascinamento o un adattamento le dà. Per default 20 e 1200.
fitPaddingSpazio extra per padding, icone o badge dell’app, aggiunto al testo più largo del titolo o delle celle quando si adatta la colonna.
align"start" (il default), "center" o "end", per i numeri. Vale sia per le celle sia per il titolo.
sortableIl suo titolo ha un pulsante di ordinamento che richiede un ordinamento (vedi Ordinamento).
fixedResta a sinistra mentre le altre colonne scorrono sotto di essa. Le colonne fisse precedono le altre, nel loro ordine.
resizable, movableIndicano se trascinarne il bordo la ridimensiona e se trascinarne il titolo la sposta. Per default i valori resizableColumns e movableColumns della tabella.
selectableIndica se partecipa alla selezione. Una colonna di pulsanti o checkbox imposta false. Per default true.
cellClassClassi delle celle della colonna, dopo quelle della parte cell: padding o allineamento di una sola colonna.
headerClassClassi del titolo della colonna, dopo quelle della parte headerCell.
positiveClassClassi delle celle della colonna che contengono un rialzo: un numero maggiore di zero, o un testo che inizia con +.
negativeClassClassi delle celle della colonna che contengono un ribasso: un numero minore di zero, o un testo che inizia con -.

rowHeight è l’altezza di una riga del corpo (default 32) e headerHeight l’altezza di una riga di titoli (default l’altezza della riga). rowHeader aggiunge a sinistra una colonna di numeri di riga, che seleziona le righe. stripe assegna alle righe dispari la parte rowOdd.

#Etichette di gruppo

groups colloca etichette sopra le colonne, partendo dal livello più basso. Ogni livello è un elenco di { label, span } le cui estensioni sommano al numero di colonne, o al numero di elementi del livello inferiore.

<DataTable
  columns={columns}
  data={rows}
  groups={[
    [{ label: "Person", span: 2 }, { label: "Result", span: 1 }],
  ]}
  class="flex-1"
/>

#Un numero qualsiasi di righe

La tabella richiede le righe per posizione e l’app le fornisce. rowCount è il numero totale di righe, data le righe che l’app possiede e dataStart la posizione della prima di esse. Le righe al di fuori di data restano vuote finché l’app non le fornisce. onVisibleRowsChange segnala le righe in vista, { range: { start, end } }, a ogni passo di scorrimento, ed è il punto in cui recuperare la pagina che le circonda.

const ROWS = 1_000_000;
const page = signal({ start: 0, rows: load(0) });

<DataTable
  columns={columns}
  data={page().rows}
  dataStart={page().start}
  rowCount={ROWS}
  onVisibleRowsChange={({ range: { start, end } }) => {
    // Keep the rows in view inside the page held.
    const held = page();
    if (start < held.start || end > held.start + held.rows.length) {
      const first = Math.max(0, start - 200);
      page.set({ start: first, rows: load(first) });
    }
  }}
  class="flex-1"
/>

Per un elenco che cresce in coda, imposta hasMore: onLoadMore scatta una volta per ogni numero di righe quando le righe in vista arrivano entro loadMoreThreshold (default 20) dall’ultima. Mentre loading è true attende, e lo slot loadingView viene mostrato sopra le righe. Lo slot empty viene mostrato quando non ci sono righe.

Oltre qualche milione di punti di contenuto le barre di scorrimento coprono un intervallo scalato, così un milione di righe scorre comunque fino a ciascuna riga.

#Selezione

Tre interruttori decidono che cosa seleziona una pressione, come in gpui-component:

PropUna pressione selezionaselection
rowSelectable (default true)Una riga: una qualsiasi delle sue celle, o la sua intestazione di riga{ row }
columnSelectable (default true)Una colonna: il suo titolo{ column }
cellSelectable (default false)Una cella; l’intestazione di riga (mostrata per default insieme a essa) seleziona le righe{ row, column }

Con cellSelectable e l’intestazione di riga nascosta (rowHeader={false}), premere di nuovo la cella selezionata ne seleziona la riga. Una pressione con Maiusc o con il tasto comando della piattaforma premuto seleziona una riga solo finché selectOnModifierPress (default true), perciò un’app che mantiene una propria selezione multipla di righe gestisce da sé quelle pressioni: onRowPress segnala ogni pressione sul corpo con la sua riga, la colonna sotto il puntatore, i clic in una riga e i tasti modificatori premuti. Una colonna il cui selectable è false non seleziona né se stessa né le proprie celle.

Le righe si contano da 0 nei dati, e una colonna è il suo indice tra columns, indipendentemente dall’ordine in cui l’utente le ha spostate. onSelectionChange segnala ciò che l’utente ha selezionato (null per nulla). La prop selection imposta la selezione dall’app; se non la imposti, la tabella la mantiene da sé. onDoublePress segnala una riga, una cella o un titolo premuti due volte, e onContextMenu una pressione secondaria o prolungata con il punto in cui aprire il Menu dell’app. Entrambi indicano la cella sotto il puntatore (il suo row e il suo column), il numero di una riga (solo row) o un titolo (solo column). Fino alla pressione successiva, la cella per cui è stato richiesto un menu ha la parte cellActive, oppure la sua riga ha la parte rowActive dove le celle non si selezionano.

Gli screen reader ricevono una griglia (nominata da accessibilityLabel) di intestazioni di colonna e celle, con quelle selezionate annunciate come tali.

#Tastiera

Premere la tabella, o raggiungerla con Tab (macOS, web), le dà la tastiera fino a un’altra pressione, a un cambio di focus altrove o a blur(); focus() la assegna dall’app. La tabella è una sola tappa di Tab: al suo interno Tab sposta la selezione, ed Escape restituisce la tastiera.

TastiCosa fanno
Tasti frecciaSpostano la selezione di una riga, una colonna o una cella, facendola scorrere in vista.
Tab, Maiusc+TabPassano alla colonna successiva o precedente.
Pag su, Pag giùSi spostano di una pagina di righe.
Home, FinePassano alla prima o all’ultima.
EscapeCancella la selezione, poi restituisce la tastiera.
Scorciatoia di copiaMette negli appunti il testo della selezione (copy()).

loopSelection (default true) fa sì che i tasti freccia proseguano oltre le estremità.

#Ordinamento

Una colonna sortable ha un pulsante di ordinamento in fondo al titolo, un piccolo pulsante ghost attenuato finché la colonna non è ordinata. Premerlo segnala l’ordinamento successivo ({ key, direction }) nel ciclo non ordinato, crescente, decrescente e di nuovo non ordinato, con onSortChange({ sort }) (null per annullare). La tabella non riordina le righe: l’app ordina i propri dati, o chiede al server le righe nel nuovo ordine, e imposta sort perché il titolo lo mostri. Poiché l’ordine appartiene all’app, l’ordinamento funziona allo stesso modo su un milione di righe che l’app non possiede mai per intero.

<DataTable
  columns={columns}
  data={rows()}
  sort={sort()}
  onSortChange={({ sort: next }) => {
    sort.set(next ?? undefined);
    rows.set(sorted(people, next));
  }}
  class="flex-1"
/>

#Ridimensionare e spostare le colonne

Trascinare il bordo finale di una colonna la ridimensiona entro minWidth e maxWidth, e onColumnResize({ key, width }) segnala ogni passo. Premere due volte di seguito il bordo adatta la colonna al suo testo e al suo titolo più larghi. Trascinare un titolo sposta la colonna, e una linea indica dove verrà rilasciata; onColumnMove segnala { key, from, to, order }, dove order sono i key di tutte le colonne nell’ordine mostrato. Le colonne fisse restano tra quelle fisse. resizableColumns e movableColumns disattivano entrambi i comportamenti per la tabella, e resizable e movable di una colonna prevalgono su di essi.

#Dati in tempo reale

Una tabella di quotazioni cambia molte volte al secondo. L’app formatta le righe in vista e un margine attorno ad esse (le conosce da onVisibleRowsChange) e le passa come data da dataStart, così un aggiornamento costa quanto ciò che è sullo schermo, qualunque sia il numero di righe. Rialzi e ribassi prendono i colori da positiveClass e negativeClass della colonna, applicati in modo nativo alle celle il cui valore è sopra o sotto zero (o il cui testo inizia con + o -).

const tone = { positiveClass: "text-green-600", negativeClass: "text-red-600" };
const columns: DataTableColumn[] = [
  { key: "symbol", title: "Symbol", fixed: true },
  { key: "price", title: "Price", align: "end", sortable: true },
  { key: "change", title: "Chg%", align: "end", ...tone },
];

Righe e colonne sono slot che la tabella crea una volta sola e conserva: lo scorrimento assegna loro altre righe e colonne da mostrare, perciò uno scorrimento, per quanto lungo, cambia solo testi e posizioni.

#Disegnare celle e titoli

renderCell disegna le celle proprie dell’app dove una colonna non è solo testo (un badge, un pulsante). Viene chiamato solo per le celle in vista, con un DataTableCell: row, column, key, text (ciò che la tabella mostrerebbe) e selected. L’app cerca i propri dati tramite row. renderHeaderCell disegna un titolo su tutta la sua cella, ricevendo un DataTableHeaderCell: column, key, title, sort (la direzione, oppure nessuna) e selected.

<DataTable
  columns={columns}
  data={rows()}
  renderCell={(cell) =>
    cell.key === "status" ? (
      <View class={cell.text === "open" ? "rounded bg-green-500/20 px-2" : "rounded bg-muted px-2"}>
        <Text class="text-xs">{cell.text}</Text>
      </View>
    ) : (
      <Text class="px-2 text-sm">{cell.text}</Text>
    )
  }
  class="flex-1"
/>

fontFamily e fontSize (default 14) impostano il font delle celle, nel quale la tabella misura anche i testi per adattare le colonne.

#Il ref

ref restituisce un DataTableRef. Un metodo che riceve una riga, una colonna o una chiave di colonna che la tabella non ha non cambia nulla e registra un avviso con il nome del metodo e il valore; fitColumn viene rifiutato con un TypeError per una chiave sconosciuta.

MetodoDescrizione
scrollToRow(row, animated?)Fa scorrere una riga in vista.
scrollToColumn(key, animated?)Fa scorrere una colonna in vista.
selection()Ciò che è selezionato, null per nulla.
select(selection)Seleziona (null: nulla) e porta in vista, senza onSelectionChange.
visibleRows(), visibleColumns()Le righe e le colonne scorrevoli in vista, come { start, end } (end escluse).
columnWidths()Le larghezze attuali, nell’ordine di columns.
setColumnWidth(key, width)Imposta la larghezza di una colonna, entro i suoi limiti.
fitColumn(key)Imposta una colonna larga quanto richiedono il suo testo e il suo titolo più larghi, tra le righe in vista e fino a mille in più attorno ad esse. Restituisce la larghezza.
dump(start?, end?)I testi delle righe indicate (default tutte quelle possedute) e dei titoli, come mostrati: { headers, rows }, per l’esportazione.
copy()Mette negli appunti il testo della selezione: le celle di una riga separate da tabulazioni, quelle di una colonna da interruzioni di riga, il testo di una cella.
focus(), blur()Dà la tastiera alla tabella o la toglie.
menuTarget(), clearMenuTarget()Ciò per cui è stato richiesto l’ultimo menu contestuale ({ row?, column? }, segnato da cellActive / rowActive), e la rimozione di quel segno quando il menu dell’app si chiude.

#Stilizzare le parti

class e style stilizzano il riquadro della tabella. classes accetta classi Tailwind per parte e styles stili inline per parte; le parti forniscono la struttura e l’allineamento della tabella; le loro classi forniscono l’aspetto, e styles prevalgono sulle classi.

<DataTable
  columns={columns}
  data={rows()}
  stripe
  class="flex-1 rounded-lg border border-border"
  classes={{
    header: "bg-secondary",
    headerCell: "pl-2 pr-1",
    headerContent: "gap-1",
    cell: "px-2",
    resizeHandle: "bg-border group-hover:bg-primary",
    sortAscending: "text-muted-foreground opacity-60 selected:text-foreground selected:opacity-100",
    sortDescending: "text-muted-foreground opacity-60 selected:text-foreground selected:opacity-100",
    rowSelected: "bg-primary/10",
    rowHover: "bg-muted/50",
    fixedEdge: "bg-border",
  }}
/>
ParteChe cos’è
rootIl riquadro della tabella: bordo, raggio e sfondo
headerL’intestazione lungo la tabella, con le sue righe di etichette di gruppo e titoli
groupCellUn’etichetta di gruppo sopra le colonne che comprende
headerCellLa cella del titolo di ogni colonna
headerContentLa riga di layout dell’etichetta e del pulsante di ordinamento; imposta qui la loro spaziatura
headerCellDraggingIl titolo trascinato, dopo headerCell
headerCellSortedIl titolo della colonna per cui la tabella è ordinata, dopo headerCell
headerCellSelectedIl titolo della colonna selezionata, dopo headerCell
sortIndicatorIl pulsante di ordinamento di una colonna ordinabile
sortAscending, sortDescendingI suoi due chevron; selected: si applica alla direzione di ordinamento
resizeHandleLa linea sul bordo finale di una colonna che un trascinamento ridimensiona
moveIndicatorLa linea dove verrà rilasciata una colonna trascinata
rowOgni riga del corpo
rowOddLe righe dispari, dopo row (stripe)
rowHoverLa riga sopra cui si trova il puntatore, dopo row
rowSelectedLa riga selezionata, dopo row
rowActiveLa riga per cui è stato richiesto un menu contestuale dove le celle non si selezionano, fino alla pressione successiva, dopo row
cellOgni cella del corpo
cellSelectedLa cella selezionata, dopo cell
cellActiveLa cella per cui è stato richiesto un menu contestuale, fino alla pressione successiva, dopo cell
cellColumnSelectedLe celle della colonna selezionata, dopo cell
rowHeaderLe celle di intestazione di riga, i numeri di riga
rowHeaderCornerL’angolo sopra le intestazioni di riga
fixedEdgeLa linea sul bordo finale delle colonne fisse, sopra le colonne che scorrono sotto di esse
emptyIl riquadro dello slot empty

#Proprietà

PropRustTipoPredefinitoDescrizione
columns.columns(..)DataTableColumn[][]Le colonne, da sinistra a destra. Quelle fisse vengono per prime.
data.data(..)Row[][]Le righe: oggetti indicizzati per colonna key, oppure array indicizzati per posizione.
rowCount.row_count(..)numberle righe contenuteQuante righe ci sono in totale.
dataStart.data_start(..)number0L’indice della riga corrispondente alla prima riga di data.
rowClasses.row_classes(..)string[][]Classi delle righe indicate, in base alla loro posizione in data: l’aspetto proprio di una riga, senza chiamate a JS per ogni riga.
rowHeight.row_height(..)number32L’altezza di una riga del corpo, in punti.
headerHeight.header_height(..)numberl’altezza della rigaL’altezza di una riga del titolo.
groups.groups(..)DataTableColumnGroup[][][]Etichette sopra le colonne, a partire dal livello più basso.
sort.sort(..)DataTableSortIl criterio di ordinamento dei dati, mostrato nel titolo.
rowSelectable.row_selectable(..)booleantruePressioni e tasti selezionano le righe.
columnSelectable.column_selectable(..)booleantrueLa pressione su un titolo ne seleziona la colonna, e i tasti orizzontali spostano tra le colonne.
cellSelectable.cell_selectable(..)booleanfalsePressioni e tasti selezionano le celle.
selectOnModifierPress.select_on_modifier_press(..)booleantrueUna pressione con Maiusc o il tasto Comando premuto seleziona una riga.
selection.selection(..)DataTableSelectionCiò che è selezionato, quando è l’app a impostarlo.
loopSelection.loop_selection(..)booleantrueI tasti freccia proseguono oltre le estremità.
accessibilityLabel.accessibility_label(..)stringnessunoIl nome con cui gli screen reader identificano la tabella.
rowHeader.row_header(..)booleanmostrato con cellSelectableUna colonna di numeri di riga a sinistra.
stripe.stripe(..)booleanfalseLe righe dispari ricevono la parte rowOdd.
resizableColumns.resizable_columns(..)booleantrueIl trascinamento del bordo di una colonna la ridimensiona.
movableColumns.movable_columns(..)booleantrueIl trascinamento di un titolo sposta la sua colonna.
loading.loading(..)booleanfalseLa tabella è in caricamento: onLoadMore attende e loadingView viene mostrato.
hasMore.has_more(..)booleanfalseCi sono altre righe da caricare.
loadMoreThreshold.load_more_threshold(..)number20A quante righe dall’ultima scatta onLoadMore.
fontFamily.font_family(..)stringereditatoIl font delle celle.
fontSize.font_size(..)number14La dimensione del font delle celle, in punti.
scrollbar.scrollbar(..)booleantrueLe barre di scorrimento.
verticalScrollbar, horizontalScrollbar.vertical_scrollbar(..), .horizontal_scrollbar(..)booleanscrollbarLa barra di scorrimento di un asse (quella orizzontale è la barra dei desktop sotto la tabella).
bounces.bounces(..)booleantrueSe lo scorrimento rimbalza alle estremità, dove la piattaforma lo prevede.
renderCell.render_cell(..)(cell: DataTableCell) => JSX.ElementDisegna le celle visibili.
renderHeaderCell.render_header_cell(..)(cell: DataTableHeaderCell) => JSX.ElementDisegna i titoli.
empty.empty(..)JSX.ElementCiò che viene mostrato quando non ci sono righe.
loadingView.loading_view(..)JSX.ElementCiò che viene mostrato sopra le righe mentre loading.
classes.classes(..)DataTableClasses{}Classi Tailwind per parte.
styles.styles(..)DataTableStyles{}Stili inline per parte, sopra le classi.
class, stylemetodi di stilestring, StyleProp<ViewStyle>Il box della tabella.

#Eventi

EventoRustDescrizione
onSelectionChange.on_selection_change(|selection: &Option<DataTableSelection>| ..)L’utente ha cambiato la selezione: { selection }, un { row?, column? } o null.
onRowPress.on_row_press(|event: &DataTablePress| ..)Una riga o una cella è stata premuta: { row, column?, clicks, shift, control, alt, platform }.
onDoublePress.on_double_press(|target: &DataTableTarget| ..)Una riga, una cella o un titolo è stato premuto due volte: { target }, un { row?, column? }.
onContextMenu.on_context_menu(|event: &DataTableContextMenu| ..)È stato richiesto un menu contestuale: { row?, column?, x, y }, il punto nella vista radice.
onSortChange.on_sort_change(|sort: &Option<DataTableSort>| ..)È stato premuto un pulsante di ordinamento: { sort }, il successivo ordinamento { key, direction } o null.
onColumnResize.on_column_resize(|key: &SharedString, width: &Points| ..)Una colonna è stata ridimensionata ({ key, width }), a ogni passo di un trascinamento e ancora una volta quando un adattamento la imposta.
onColumnMove.on_column_move(|event: &DataTableColumnMove| ..)Una colonna è stata spostata: { key, from, to, order }.
onVisibleRowsChange.on_visible_rows_change(|range: &DataTableRange| ..)Le righe visibili sono cambiate: { range }, un { start, end }. Recupera le righe da qui.
onVisibleColumnsChange.on_visible_columns_change(|range: &DataTableRange| ..)Le colonne scorrevoli visibili sono cambiate: { range }.
onLoadMore.on_load_more(|| ..)Le righe visibili sono arrivate entro loadMoreThreshold dall’ultima mentre hasMore e non loading.

#Correlati

  • Editor e DiffView: gli altri componenti di base ad alta intensità di dati.
  • Menu: il menu da aprire a partire da onContextMenu.
  • nsh/base: gli altri componenti di base.