InteraktionGilt fürSuperScheduler Pro
Ressourcenbäume, Spalten und Auswahl
Setzen Sie treeEnabled und verschachteln Sie Ressourcen in children; ein Elternknoten bleibt eingeklappt, sofern er nicht expanded: true hat. Spalten im Zeilenkopf ergänzen Sie mit rowHeaderColumns, deren Zellen über display aus Feldern der Ressource gefüllt werden. Filtern Sie mit control.rows.filter() und control.events.filter() zusammen mit onRowFilter und onEventFilter, und wählen Sie aus mit eventClickHandling: 'Select', Rechteckauswahl, rowClickHandling: 'Select' sowie den APIs multiselect und multirange.
Echte Planungen haben selten eine flache Liste von Ressourcen. Zimmer gehören zu Etagen, Techniker zu Regionen, Maschinen zu Linien. Dieser Leitfaden behandelt die Pro-Funktionen, die Zeilen ordnen und mit mehreren Elementen gleichzeitig arbeiten: Ressourcenbäume, Spalten im Zeilenkopf, Filter und die drei Arten der Auswahl (Ereignisse, Zeilen und Zeiträume).
Alles hier erfordert SuperScheduler Pro (super-scheduler). Die Edition Lite rendert eine flache Liste und lehnt children und columns an Ressourcen ab.
Ressourcen in einem Baum gruppieren
Ein Baum besteht aus einfachen Daten: Eine Ressource mit einem children-Array wird zur Elternzeile. Zwei Dinge schalten ihn ein:
treeEnabled: trueam Planer. Ohne diese Option werdenchildrenignoriert, und der Zeilenkopf hat keine Umschalter.expanded: truean jedem Elternknoten, der geöffnet starten soll. Elternknoten sind eingeklappt, sofernexpandednicht genautrueist.
import { useMemo } from 'react'
import { SuperSchedulerComponent, useSchedulerControl } from 'super-scheduler'
import type { SuperScheduler } from 'super-scheduler'
import 'super-scheduler/styles.css'
// Regions are parent rows and technicians their children. A parent stays collapsed
// unless its resource says `expanded: true`.
const RESOURCES: SuperScheduler.ResourceData[] = [
{
id: 'north',
name: 'North region',
expanded: true,
children: [
{ id: 'ana', name: 'Ana Ruiz' },
{ id: 'ben', name: 'Ben Ortiz' },
],
},
{
id: 'south',
name: 'South region',
children: [
{ id: 'cai', name: 'Cai Moreno' },
{ id: 'dee', name: 'Dee Patel' },
],
},
]
const JOBS: SuperScheduler.EventData[] = [
{
id: 'job-1',
resource: 'ana',
start: '2026-10-05T00:00:00',
end: '2026-10-07T00:00:00',
text: 'Panel upgrade',
},
{
id: 'job-2',
resource: 'cai',
start: '2026-10-06T00:00:00',
end: '2026-10-09T00:00:00',
text: 'Boiler service',
},
]
export function TeamPlanner() {
const { controlRef, control } = useSchedulerControl()
// The control adopts the events array and mutates it: hand it a copy.
const events = useMemo(() => JOBS.slice(), [])
return (
<section aria-labelledby="team-plan-title">
<h2 id="team-plan-title">Field teams</h2>
<div role="toolbar" aria-label="Rows">
<button type="button" disabled={control === null} onClick={() => control?.rows.expandAll()}>
Expand all
</button>
<button
type="button"
disabled={control === null}
onClick={() => control?.rows.collapseAll()}
>
Collapse all
</button>
</div>
<SuperSchedulerComponent
controlRef={controlRef}
startDate="2026-10-05"
days={14}
scale="Day"
cellWidth={56}
treeEnabled
treeIndent={16}
// Region rows group technicians: no jobs and no time selection on them.
treePreventParentUsage
resources={RESOURCES}
events={events}
/>
</section>
)
}Sie sollten „North region“ geöffnet mit beiden Technikern sehen und „South region“ geschlossen; beide Buttons funktionieren, sobald der Planer gemountet ist (bis dahin ist control null).
Zugehörige Optionen:
| Option | Standard | Wirkung |
|---|---|---|
treeEnabled | false | Baut Zeilen aus children auf. |
treeIndent | 20 | Einrückung pro Ebene, in Pixeln. |
treePreventParentUsage | false | Elternzeilen nehmen weder Ereignisse noch eine Zeitauswahl an. |
treeAutoExpand | true | Ein eingeklappter Elternknoten öffnet sich, wenn eine halbe Sekunde lang ein Ereignis über ihn gezogen wird. |
rowFilterParentsAlwaysVisible | true | Behält die Vorfahren einer Zeile, die einem Filter entspricht. |
Elternknoten können auch Ereignisse enthalten (eine Buchung für das „ganze Team“), sofern Sie nicht treePreventParentUsage setzen. Eine einzelne Ressource lehnt abgelegte Ereignisse mit preventUsage: true ab, und Ressourcen der obersten Ebene lassen sich mit frozen: 'top' oder frozen: 'bottom' über oder unter den scrollenden Zeilen fixieren, was sich für Summenzeilen eignet.
Aus Code auf- und zuklappen
Das Control stellt den Baum über control.rows bereit:
control.rows.expandAll()undcontrol.rows.collapseAll();control.rows.expand(level)öffnet die Elternknoten oberhalb einer Ebene (standardmäßig1,-1für alle Ebenen);control.rows.find(id)gibt eine Zeile zurück;row.expand(),row.collapse()undrow.toggle()ändern sie.
onResourceExpand und onResourceCollapse melden ein Umschalten, nachdem es passiert ist, mit der Zeile als args.resource. Nutzen Sie sie, um sich zu merken, was der Nutzer geöffnet hat, oder um andere Teile Ihrer Oberfläche synchron zu halten.
Spalten im Zeilenkopf ergänzen
Ohne rowHeaderColumns zeigt der Zeilenkopf den name jeder Ressource. Mit der Option wird der Kopf zu einer kleinen Tabelle:
textist der Spaltentitel (nameundtitlewerden ebenfalls akzeptiert);displaybenennt ein Feld der Ressource, dessen Wert die Zelle füllt (ein gleichnamiges Feld intagswird zuerst gelesen);- die erste Spalte zeigt den
nameder Ressource, wenn sie keindisplayhat; widthlegt die Breite in Pixeln fest (StandardrowHeaderColumnDefaultWidth, 80);sortmacht den Titel klickbar: Ein Klick sortiert die Zeilen nach diesem Feld, erst aufsteigend, dann absteigend, und setztaria-sortam Titel.
Eine Ressource kann auch eigene columns: [{ text }, { html }] mitbringen. Diese Einträge werden nach Position zugeordnet, einer pro Spalte.
import { useState } from 'react'
import { type SuperScheduler, SuperSchedulerComponent } from 'super-scheduler'
import 'super-scheduler/styles.css'
type Status = 'available' | 'off'
const TECHNICIANS: SuperScheduler.ResourceData[] = [
{ id: 'ana', name: 'Ana Ruiz', skill: 'Electrical', shift: 'Early', status: 'available' },
{ id: 'ben', name: 'Ben Ortiz', skill: 'HVAC', shift: 'Late', status: 'off' },
{ id: 'cai', name: 'Cai Moreno', skill: 'Plumbing', shift: 'Early', status: 'available' },
]
// `display` reads a resource field, so a column keeps its values when it is reordered.
// `sort` makes the title clickable: it sorts the rows by that field, ascending then descending.
const INITIAL_COLUMNS: SuperScheduler.RowHeaderColumnData[] = [
{ text: 'Technician', width: 150, sort: 'name' },
{ text: 'Skill', display: 'skill', width: 110, sort: 'skill' },
{ text: 'Shift', display: 'shift', width: 70, nonresizable: true },
{ text: 'Status', display: 'status', width: 100 },
]
const STATUS_LABEL: Record<Status, string> = { available: 'Available', off: 'Day off' }
// Runs with `this` = the control, whose rowHeaderColumns are always in the current order.
function decorateStatus(
this: SuperScheduler.SchedulerApi,
args: SuperScheduler.SchedulerBeforeRowHeaderRenderArgs,
): void {
const index = this.rowHeaderColumns?.findIndex((column) => column.display === 'status') ?? -1
const cell = args.row.columns[index]
const status = args.row.data.status
if (cell === undefined || (status !== 'available' && status !== 'off')) return
// With rowHeaderColumns, row.html is ignored: write the column's own html (trusted markup).
cell.html = `<span class="tech-status tech-status--${status}">${STATUS_LABEL[status]}</span>`
}
export function TechnicianColumns({ events }: { events: SuperScheduler.EventData[] }) {
// Kept in state so a parent re-render never hands the control the original order again.
const [columns, setColumns] = useState(INITIAL_COLUMNS)
return (
<SuperSchedulerComponent
startDate="2026-10-05"
days={14}
scale="Day"
cellWidth={56}
resources={TECHNICIANS}
events={events}
rowHeaderColumns={columns}
rowHeaderColumnsReorderable
onRowHeaderColumnsChange={(args) => setColumns([...args.columns])}
onBeforeRowHeaderRender={decorateStatus}
/>
)
}Um eine Zelle zu gestalten, verwenden Sie onBeforeRowHeaderRender. Mit Spalten wird das eigene html der Zeile ignoriert: Schreiben Sie stattdessen args.row.columns[i].html. Dieses Markup ist vertrauenswürdiges HTML; escapen Sie Nutzertext also mit SuperScheduler.Util.escapeHtml. Für React-Inhalte im Zeilenkopf siehe React-Render-Slots.
Spaltenbreite ändern und Spalten umordnen
Die Breite von Spalten lässt sich standardmäßig ändern (rowHeaderColumnsResizable: true); nonresizable: true schaltet das für eine einzelne Spalte ab. Nach einer Größenänderung schreibt das Control die neue Breite in dieses Spaltenobjekt Ihres rowHeaderColumns-Arrays und ruft onRowHeaderColumnResized({ column }) auf.
Das Umordnen ist standardmäßig aus. Mit rowHeaderColumnsReorderable ziehen Nutzer die Spaltentitel; die Ränder zur Größenänderung haben dabei Vorrang vor dem Ziehen. In keyboardMode: 'Full' verschieben Alt + Umschalt + Links und Alt + Umschalt + Rechts den fokussierten Titel und sagen die Änderung an. Aus Code verschiebt control.moveRowHeaderColumn(from, to) eine Spalte anhand ihres Index in der aktuellen Reihenfolge.
Jede Größenänderung und jedes Umordnen ruft onRowHeaderColumnsChange auf mit:
columns: den Spalten in ihrer neuen Reihenfolge, mit ihren Breiten;order:order[i]ist der ursprüngliche Index (in der übergebenen Prop) der Spalte, die jetzt an Positionisteht;widthsundreason('resize'oder'reorder').
Halten Sie die Spalten wie im Snippet im React-State und übernehmen Sie args.columns. Andernfalls würde eine Elternkomponente, die mit einem neuen Array-Literal neu rendert, dem Control die ursprüngliche Reihenfolge zurückgeben.
Zeilen und Ereignisse filtern
Filter bestehen aus einem Parameter und einem Callback. control.rows.filter(param) speichert den Parameter und ruft onRowFilter für jede Zeile auf; setzen Sie args.visible = false, um sie auszublenden. control.events.filter(param) und onEventFilter funktionieren für Ereignisse genauso. Ein Parameter, der falsy ist ('', null, 0), hebt den Filter auf.
import { useEffect, useMemo, useState } from 'react'
import { SuperSchedulerComponent, useSchedulerControl } from 'super-scheduler'
import type { SchedulerProps, SuperScheduler } from 'super-scheduler'
type JobStatus = 'scheduled' | 'done' | 'cancelled'
type Job = { status: JobStatus }
// Module-level handlers keep their identity: a new onRowFilter or onEventFilter
// function makes the control evaluate the active filter again.
const FILTERS: Pick<SchedulerProps, 'onRowFilter' | 'onEventFilter'> = {
onRowFilter: (args) => {
const query = String(args.filterParam).toLowerCase()
args.visible = args.row.name.toLowerCase().includes(query)
},
onEventFilter: (args) => {
const job = args.e.data as SuperScheduler.EventData<Job>
args.visible = job.status === args.filterParam
},
}
export function FilteredJobs(props: {
resources: SuperScheduler.ResourceData[]
jobs: SuperScheduler.EventData<Job>[]
}) {
const { controlRef, control } = useSchedulerControl()
const [query, setQuery] = useState('')
const [status, setStatus] = useState<JobStatus | ''>('')
const events = useMemo(() => props.jobs.slice(), [props.jobs])
// A falsy parameter ('' or null) clears the filter.
useEffect(() => control?.rows.filter(query.trim() || null), [control, query])
useEffect(() => control?.events.filter(status || null), [control, status])
return (
<>
<label>
Technician <input type="search" value={query} onChange={(e) => setQuery(e.target.value)} />
</label>
<label>
Status
<select value={status} onChange={(e) => setStatus(e.target.value as JobStatus | '')}>
<option value="">All</option>
<option value="scheduled">Scheduled</option>
<option value="done">Done</option>
<option value="cancelled">Cancelled</option>
</select>
</label>
<SuperSchedulerComponent
{...FILTERS}
controlRef={controlRef}
startDate="2026-10-05"
days={14}
scale="Day"
treeEnabled
// Keeps the region row of every matching technician (default true).
rowFilterParentsAlwaysVisible
resources={props.resources}
events={events}
/>
</>
)
}Die Eingabe „ben“ lässt „North region“ und „Ben Ortiz“ übrig: rowFilterParentsAlwaysVisible behält die Vorfahren jeder passenden Zeile. Die Wahl eines Status blendet die anderen Ereignisse aus, ohne die Zeilen anzutasten.
Filter laufen im Browser über die Daten, die das Control hält. Eine Suche über Daten, die nicht geladen sind (ein anderer Monat, ein anderer Standort), ist eine Abfrage an Ihr Backend, gefolgt von neuen resources oder events.
Ereignisse auswählen
Standardmäßig führt ein Klick auf ein Ereignis nur onEventClick aus. Für die Auswahl braucht es eventClickHandling: 'Select':
- Ein Klick schaltet die Auswahl des Ereignisses um und hebt die übrigen auf.
- Strg + Klick (Cmd + Klick unter macOS) schaltet es um und behält die übrigen, solange
allowMultiSelecttrueist (der Standard). - Mit
eventMultiSelectRangewählt Umschalt + Klick die Ereignisse zwischen dem zuletzt angeklickten und diesem aus, über die sichtbaren Zeilen hinweg; Strg/Cmd + Umschalt fügt sie hinzu.
onEventSelect läuft vor der Änderung und kann sie mit args.preventDefault() abbrechen; onEventSelected läuft danach.
Die API control.multiselect liest und ändert die Auswahl: get(), add(e), remove(e), clear(), isSelected(e) und selectAll({ scope, filter }). selectAll wählt standardmäßig die sichtbaren Ereignisse aus; scope: 'all' durchsucht jedes geladene Ereignis, mit Kosten proportional zur Größe des Speichers.
import { useEffect, useMemo, useState } from 'react'
import { SuperSchedulerComponent, useSchedulerControl } from 'super-scheduler'
import type { SchedulerProps, SuperScheduler } from 'super-scheduler'
import { subscribeScheduler } from 'super-scheduler/hooks'
type Job = { status: 'scheduled' | 'done' }
export function SelectableJobs(props: {
resources: SuperScheduler.ResourceData[]
jobs: SuperScheduler.EventData<Job>[]
onReschedule: (ids: SuperScheduler.EventId[]) => void
}) {
const { controlRef, control } = useSchedulerControl()
const [count, setCount] = useState(0)
const events = useMemo(() => props.jobs.slice(), [props.jobs])
// Rectangle selections and multiselect calls (selectAll, clear) publish the
// 'selection' topic; clicks are reported by onEventSelected below.
useEffect(() => {
if (control === null) return
return subscribeScheduler(control, 'selection', (selected) => setCount(selected.length))
}, [control])
const config = useMemo<SchedulerProps>(
() => ({
// A click toggles the event; Ctrl+click (Cmd+click on macOS) keeps the others.
eventClickHandling: 'Select',
// Shift+click selects every event between the last clicked one and this one.
eventMultiSelectRange: true,
// Shift+drag over the grid selects the events inside the rectangle.
rectangleSelectHandling: 'EventSelect',
// With the rectangle: Shift adds to the selection, Alt removes from it.
rectangleSelectModifiers: true,
onEventSelected() {
setCount(this.multiselect.get().length)
},
// Marks selected events for CSS. The hook runs again for every event whose
// selection changes.
onBeforeEventRender: (args) => {
const e = args.control.events.find(args.data.id)
if (e !== null && args.control.multiselect.isSelected(e)) {
args.data.cssClass = [args.data.cssClass, 'is-selected'].filter(Boolean).join(' ')
}
},
}),
[],
)
const selectScheduled = () =>
control?.multiselect.selectAll({
scope: 'view',
filter: (e) => (e.data as SuperScheduler.EventData<Job>).status === 'scheduled',
})
const reschedule = () => {
const ids = control?.multiselect.get().map((e) => e.id()) ?? []
if (ids.length > 0) props.onReschedule(ids)
}
return (
<>
<div role="toolbar" aria-label="Selection">
<button type="button" onClick={selectScheduled}>
Select scheduled in view
</button>
<button type="button" onClick={() => control?.multiselect.clear()}>
Clear
</button>
<button type="button" disabled={count === 0} onClick={reschedule}>
Reschedule {count} {count === 1 ? 'job' : 'jobs'}
</button>
</div>
<SuperSchedulerComponent
{...config}
controlRef={controlRef}
startDate="2026-10-05"
days={14}
scale="Day"
resources={props.resources}
events={events}
/>
</>
)
}Der Zähler im Button sollte Klicks, Rechtecken und den Aktionen der Werkzeugleiste folgen, und ausgewählte Aufträge sollten durch dieses CSS umrandet sein:
.super-scheduler__event.is-selected {
z-index: 2;
box-shadow: 0 0 0 2px var(--super-scheduler-accent), var(--super-scheduler-shadow-2);
}Mit allowMultiMove verschiebt das Ziehen eines ausgewählten Ereignisses die ganze Auswahl; jedes Ereignis durchläuft dieselben Verschieberegeln (siehe Ziehen, Dauer ändern und Geschäftsregeln). Im vollständigen Tastaturmodus wählt Strg/Cmd + A jedes sichtbare Ereignis aus.
Rechteckauswahl
rectangleSelectHandling bestimmt, was ein aufgezogenes Rechteck bewirkt:
'EventSelect'wählt die Ereignisse darin aus (und führt die Callbacks aus);'Enabled'führt nur die Callbacks aus, für Anwendungen, die selbst auf das Rechteck reagieren;'Disabled'(Standard) schaltet es ab.
Nutzer ziehen ein Rechteck auf, indem sie bei gedrückter Umschalttaste über das Raster ziehen. Um ohne Umschalttaste zu beginnen, setzen Sie args.action = 'RectangleSelect' in onGridMouseDown oder rufen vor dem nächsten Drücken control.multiselect.startRectangle() auf. rectangleSelectMode: 'Row' hält das Rechteck in der Zeile, in der das Drücken begann. Mit rectangleSelectModifiers fügt Umschalt zur aktuellen Auswahl hinzu und Alt entfernt daraus; ohne eine dieser Tasten ersetzt das Rechteck die Auswahl.
Die Callbacks sind onRectangleSelecting (jeder Frame; args.visible = false blendet das Rechteck aus), onRectangleSelect (abbrechbar, mit events, start, end und resources) und onRectangleSelected.
Zeilen auswählen
rowClickHandling: 'Select' sorgt dafür, dass ein Klick auf den Zeilenkopf die Zeile auswählt. Strg/Cmd schaltet eine Zeile um, und Umschalt wählt alle Zeilen ab der zuletzt angeklickten aus. Ausgewählte Zeilen tragen aria-selected="true".
import { useMemo, useState } from 'react'
import { SuperSchedulerComponent, useSchedulerControl } from 'super-scheduler'
import type { SchedulerProps, SuperScheduler } from 'super-scheduler'
export function RosterRows(props: {
resources: SuperScheduler.ResourceData[]
events: SuperScheduler.EventData[]
onNotify: (resourceIds: SuperScheduler.ResourceId[]) => void
}) {
const { controlRef, control } = useSchedulerControl()
const [selected, setSelected] = useState<readonly SuperScheduler.ResourceId[]>([])
const events = useMemo(() => props.events.slice(), [props.events])
const config = useMemo<SchedulerProps>(
() => ({
// A click on a row header selects the row; Ctrl/Cmd toggles, Shift selects a range.
rowClickHandling: 'Select',
onRowSelected() {
setSelected(this.rows.selection.get().map((row) => row.id))
},
}),
[],
)
return (
<>
<button
type="button"
disabled={selected.length === 0}
onClick={() => props.onNotify([...selected])}
>
Notify {selected.length} technicians
</button>
<button
type="button"
onClick={() => {
control?.rows.selection.clear()
setSelected([])
}}
>
Clear rows
</button>
<SuperSchedulerComponent
{...config}
controlRef={controlRef}
startDate="2026-10-05"
days={14}
scale="Day"
resources={props.resources}
events={events}
/>
</>
)
}control.rows.selection bietet get(), add(row), remove(row), isSelected(row) und clear(); diese Aufrufe heben die Zeilen sofort hervor und lösen keinen Callback aus, weshalb das Snippet nach clear() seinen eigenen State zurücksetzt. onRowSelect (abbrechbar) und onRowSelected laufen vor bzw. nach jeder Auswahl per Klick.
Die Prop selectedRows enthält die IDs der ausgewählten Ressourcen. Übergeben Sie sie, um mit einer Auswahl zu starten; das Control aktualisiert genau dieses Array, wenn sich die Auswahl ändert.
Zeiträume auswählen
Ziehen über leere Zellen wählt einen Zeitraum aus und ruft beim Loslassen einmal onTimeRangeSelected auf, mit start, end (exklusiv), resource und origin: 'drag'. Weitere Ursprünge:
'click': ein einfacher Klick auf eine leere Zelle wählt diese Zelle aus;'keyboard': bei aktivierter Tastatur die Eingabetaste auf einer fokussierten Zelle oder Umschalt + Links/Rechts, um einen Zeitraum zu erweitern;'api':control.selectTimeRange(start, end, resource).
Prüfen Sie args.origin, wenn nur ein Ziehen etwas anlegen soll. Die Auswahl bleibt nach dem Loslassen gezeichnet, bis zur nächsten Auswahl oder bis control.clearSelection(). Auch ein Klick an anderer Stelle hebt sie auf, außer mit timeRangeSelectedHandling: 'HoldForever'; 'Disabled' schaltet die Zeitraumauswahl ab.
onTimeRangeSelecting läuft bei jeder Änderung während des Ziehens. Setzen Sie args.allowed = false, um einen Zeitraum abzulehnen (der Schatten wird markiert, und das Loslassen wählt nichts aus), oder schreiben Sie args.start und args.end um, um ihn zu begrenzen. Gesperrte Zellen und Elternknoten unter treePreventParentUsage lehnen Auswahlen ohne jeden Code ab.
Mehrere Zeiträume gleichzeitig
Mit allowMultiRange kann ein neues Ziehen einen Zeitraum hinzufügen, statt den aktuellen zu ersetzen: solange Strg/Cmd gedrückt ist (multiRangeMode: 'CtrlOrMeta', der Standard) oder immer ('Always'). args.multirange listet jeden ausgewählten Zeitraum auf, und control.multirange liest oder ändert sie: get(), clear() und add(new SuperScheduler.Selection(start, end, resource)).
import { useMemo, useState } from 'react'
import { SuperScheduler, SuperSchedulerComponent, useSchedulerControl } from 'super-scheduler'
import type { SchedulerProps } from 'super-scheduler'
export interface BlockRequest {
readonly resource: SuperScheduler.ResourceId
/** ISO wall-clock values; `end` is exclusive. */
readonly start: string
readonly end: string
}
export function RangeBlocker(props: {
resources: SuperScheduler.ResourceData[]
events: SuperScheduler.EventData[]
onBlock: (requests: BlockRequest[]) => void
}) {
const { controlRef, control } = useSchedulerControl()
const [ranges, setRanges] = useState<readonly SuperScheduler.SchedulerRange[]>([])
const events = useMemo(() => props.events.slice(), [props.events])
const config = useMemo<SchedulerProps>(
() => ({
// Ctrl/Cmd + drag adds a range instead of replacing the current one.
allowMultiRange: true,
multiRangeMode: 'CtrlOrMeta',
onTimeRangeSelecting: (args) => {
// Past days cannot be blocked: the shadow turns red and the drop is refused.
args.allowed = args.start.getTime() >= SuperScheduler.Date.today().getTime()
},
onTimeRangeSelected: (args) => {
// A plain click on an empty cell also selects it (origin 'click').
setRanges([...args.multirange])
},
}),
[],
)
const block = () => {
props.onBlock(
ranges.map((range) => ({
resource: range.resource,
start: range.start.value,
end: range.end.value,
})),
)
control?.clearSelection()
setRanges([])
}
return (
<>
<button type="button" disabled={ranges.length === 0} onClick={block}>
Block {ranges.length} selected {ranges.length === 1 ? 'range' : 'ranges'}
</button>
<SuperSchedulerComponent
{...config}
controlRef={controlRef}
startDate="2026-10-05"
days={14}
scale="Day"
resources={props.resources}
events={events}
/>
</>
)
}Ziehen Sie über freie Tage eines Zimmers und dann bei gedrückter Strg-Taste (Cmd unter macOS) über die eines anderen: Der Button zeigt „Block 2 selected ranges“. Die Zeiträume erreichen onBlock als ISO-Werte in lokaler Uhrzeit mit exklusivem Ende, bereit zum Senden an Ihr Backend.
Was Ihrer Anwendung gehört
Die Bibliothek hält Bäume, Filter und Auswahlen im Browser, für die aktuelle Sitzung. Ihre Anwendung entscheidet:
- woher der Baum kommt: Zeilen sind die
resources, die Sie übergeben, und das Control fragt nie selbst nach Kindern (onLoadNodeist reserviert); - was ein Filter bedeutet, wenn Daten nicht geladen sind, und wie die Suche das Backend erreicht;
- was eine Auswahl bewirkt: Massenaktionen, die Berechtigung, sie auszuführen, und ihre Speicherung;
- ob aufgeklappte Zeilen und Spaltenlayouts ein Neuladen überstehen (siehe gespeicherte Ansichten).
Auswahlen werden nirgends gespeichert. Der Aufklappzustand lebt in den übergebenen Ressourcenobjekten, bis Sie sie ersetzen.
Siehe auch
Zimmerplanung im HotelIn Zimmer 104 tropft die Dusche. Buchen Sie den nächsten Gast um, sperren Sie das Zimmer für den Installateur und finden Sie die ausgebuchten Nächte. Planung von SchulungsräumenDie Anmeldungen sprengen den Raum. Beide Termine wählen, sehen, was für beide frei ist, zusammen verschieben und die Ansicht behalten. Disposition im technischen AußendienstEin dringender Auftrag kommt herein. Finden Sie das Team, das ihn rechtzeitig übernehmen kann.
- Tastatur, Barrierefreiheit und Touch listet die Tasten für die Auswahl auf.
- Kontrollierte Ereignisse und Callbacks erklärt, wie ausgewählte Ereignisse Ihren State erreichen.
- Koordinierte Bereiche und gespeicherte Ansichten speichert eingeklappte Zeilen und Spaltenbreiten.
Verwandte Beispiele
- Casa NomaZimmerplanung im HotelIn Zimmer 104 tropft die Dusche. Buchen Sie den nächsten Gast um, sperren Sie das Zimmer für den Installateur und finden Sie die ausgebuchten Nächte.
- MorrowPlanung von SchulungsräumenDie Anmeldungen sprengen den Raum. Beide Termine wählen, sehen, was für beide frei ist, zusammen verschieben und die Ansicht behalten.
- FieldworkDisposition im technischen AußendienstEin dringender Auftrag kommt herein. Finden Sie das Team, das ihn rechtzeitig übernehmen kann.
- FramehousePlanung einer VideoproduktionEin Dreh dauert länger. Verschieben Sie den abhängigen Schnitt, verstehen Sie warum, und nehmen Sie es zurück.