Programmatic CRUD

This sample creates, updates, and removes scheduler events with the FlexScheduler create, update, and remove methods. It also handles itemChanging and itemChanged notifications.

FlexScheduler API Reference | SchedulerDefinition API Reference

import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; // import { CollectionView, Globalize } from '@mescius/wijmo'; import * as wjcScheduler from '@mescius/wijmo.scheduler'; import { getDisplayDate, getEvents, getRooms } from './data'; // document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', init) : init(); function init() { const eventView = new CollectionView(getEvents()); const createButton = document.querySelector('#createButton'); const updateButton = document.querySelector('#updateButton'); const removeButton = document.querySelector('#removeButton'); const selectionStatus = document.querySelector('#selectionStatus'); const operationStatus = document.querySelector('#operationStatus'); const notificationStatus = document.querySelector('#notificationStatus'); let selectedItem = null; let selectedCell = null; let selectedElement = null; let nextId = 107; let changingCount = 0; let changedCount = 0; const scheduler = new wjcScheduler.FlexScheduler('#theScheduler', { itemsSource: eventView, eventFields: { subject: 'subject', start: 'start', end: 'end' }, resources: [ { fieldExpr: 'roomId', label: 'Room', dataSource: getRooms(), valueExpr: 'id', displayExpr: 'name', backgroundColorExpr: 'color', foreColorExpr: 'textColor', }, ], definition: getWeekDefinition(), displayDate: getDisplayDate(), workHours: [{ start: '08:00', end: '17:00' }], toolbarViewItems: [{ name: 'Week', key: wjcScheduler.SchedulerBuiltInViewItem.Week }], }); scheduler.hostElement.addEventListener('click', (event) => { const hit = scheduler.hitTest(event); clearVisualSelection(); if (hit.hitTestType === wjcScheduler.SchedulerHitTestType.Item) { const presentation = hit.getHitInfo(); selectedItem = presentation.item; selectedCell = null; selectedElement = hit.element; selectedElement.classList.add('demo-selected-target'); selectionStatus.replaceChildren(createIcon('bi-calendar-event'), document.createTextNode(selectedItem.subject)); } else if (hit.hitTestType === wjcScheduler.SchedulerHitTestType.Cell) { selectedItem = null; selectedCell = hit.getHitInfo(); selectedElement = hit.element; selectedElement.classList.add('demo-selected-target'); selectionStatus.replaceChildren(createIcon('bi-clock'), document.createTextNode(`Empty slot | ${formatSlot(selectedCell)}`)); } else { selectedItem = null; selectedCell = null; selectionStatus.replaceChildren(createIcon('bi-cursor'), document.createTextNode('Select an event or empty time slot')); } updateActionState(); }); scheduler.itemChanging.addHandler((_sender, args) => { changingCount++; operationStatus.textContent = `${getActionName(args.request.action)} changing`; updateNotificationStatus(); }); scheduler.itemChanged.addHandler((_sender, args) => { changedCount++; operationStatus.textContent = `${getActionName(args.request.action)} changed | ${getSourceItems().length} events`; updateNotificationStatus(); clearSelection(); }); createButton.addEventListener('click', () => { if (!selectedCell) return; scheduler.create({ id: nextId++, subject: 'New schedule event', start: selectedCell.start, end: selectedCell.end, roomId: selectedCell.resources.roomId || 'blue', }); }); updateButton.addEventListener('click', () => { if (!selectedItem) return; scheduler.update(selectedItem, { subject: selectedItem.subject.startsWith('Updated: ') ? selectedItem.subject : `Updated: ${selectedItem.subject}`, end: new Date(selectedItem.end.getTime() + 30 * 60000), }); }); removeButton.addEventListener('click', () => { if (selectedItem) scheduler.remove(selectedItem); }); function getSourceItems() { return eventView.sourceCollection; } function updateActionState() { createButton.disabled = !selectedCell; updateButton.disabled = !selectedItem; removeButton.disabled = !selectedItem; } function clearVisualSelection() { selectedElement === null || selectedElement === void 0 ? void 0 : selectedElement.classList.remove('demo-selected-target'); selectedElement = null; } function clearSelection() { clearVisualSelection(); selectedItem = null; selectedCell = null; selectionStatus.replaceChildren(createIcon('bi-cursor'), document.createTextNode('Select an event or empty time slot')); updateActionState(); } function updateNotificationStatus() { notificationStatus.textContent = `Notifications: ${changingCount} changing / ${changedCount} changed`; } updateActionState(); } function createIcon(name) { const icon = document.createElement('i'); icon.className = `bi ${name}`; icon.setAttribute('aria-hidden', 'true'); return icon; } function formatSlot(cell) { return `${Globalize.format(cell.start, 'ddd MMM d, h:mm tt')} - ${Globalize.format(cell.end, 'h:mm tt')}`; } function getActionName(action) { switch (action) { case wjcScheduler.SchedulerItemChangeAction.Create: return 'Create'; case wjcScheduler.SchedulerItemChangeAction.Update: return 'Update'; case wjcScheduler.SchedulerItemChangeAction.Remove: return 'Remove'; } } function getWeekDefinition() { const definition = wjcScheduler.createSchedulerDefinitionPreset(wjcScheduler.SchedulerBuiltInViewItem.Week); return Object.assign(Object.assign({}, definition), { rows: { bindings: [ { type: wjcScheduler.SchedulerAxisBindingType.Time, unit: wjcScheduler.SchedulerTimeUnit.Hour, visible: (args) => args.hour >= 8 && args.hour < 17, }, ], } }); }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS Wijmo Scheduler Programmatic CRUD</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet"> <!-- SystemJS --> <script src="https://cdn.jsdelivr.net/npm/systemjs@0.21.5/dist/system.src.js" integrity="sha512-skZbMyvYdNoZfLmiGn5ii6KmklM82rYX2uWctBhzaXPxJgiv4XBwJnFGr5k8s+6tE1pcR1nuTKghozJHyzMcoA==" crossorigin="anonymous"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <main class="container-fluid"> <div class="crud-toolbar" role="toolbar" aria-label="Event actions"> <div class="selection-summary"> <strong id="selectionStatus"><i class="bi bi-cursor" aria-hidden="true"></i> Select an event or empty time slot</strong> <span>Available actions follow the selected Scheduler target.</span> </div> <div class="crud-actions"> <button id="createButton" class="btn btn-primary btn-sm" type="button" disabled><i class="bi bi-plus-lg" aria-hidden="true"></i> Create</button> <button id="updateButton" class="btn btn-outline-primary btn-sm" type="button" disabled><i class="bi bi-pencil" aria-hidden="true"></i> Update</button> <button id="removeButton" class="btn btn-outline-danger btn-sm" type="button" disabled><i class="bi bi-trash3" aria-hidden="true"></i> Remove</button> </div> <div class="crud-status"> <span id="operationStatus" aria-live="polite">Ready | 6 events</span> <span id="notificationStatus">Notifications: 0 changing / 0 changed</span> </div> </div> <div id="theScheduler"></div> </main> </body> </html>
function createDate(day, hour, minute = 0) { return new Date(2026, 4, day, hour, minute); } export function getDisplayDate() { return createDate(13, 9); } export function getRooms() { return [ { id: 'blue', name: 'Blue Room', color: '#1d4ed8', textColor: '#ffffff' }, { id: 'green', name: 'Green Room', color: '#087f5b', textColor: '#ffffff' }, { id: 'violet', name: 'Studio', color: '#7e22ce', textColor: '#ffffff' }, { id: 'amber', name: 'Forum', color: '#a1420b', textColor: '#ffffff' }, ]; } export function getEvents() { return [ { id: 101, subject: 'Weekly Planning', start: createDate(11, 9), end: createDate(11, 10), roomId: 'blue' }, { id: 102, subject: 'Design Review', start: createDate(11, 13), end: createDate(11, 14, 30), roomId: 'violet' }, { id: 103, subject: 'Customer Workshop', start: createDate(12, 10), end: createDate(12, 11, 30), roomId: 'amber', }, { id: 104, subject: 'Release Checkpoint', start: createDate(13, 9, 30), end: createDate(13, 10, 30), roomId: 'green', }, { id: 105, subject: 'Partner Briefing', start: createDate(14, 14), end: createDate(14, 15, 30), roomId: 'blue', }, { id: 106, subject: 'Weekly Wrap-up', start: createDate(15, 11), end: createDate(15, 12), roomId: 'green' }, ]; }
body { color: #1f2937; font-size: 15px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; user-select: none; margin: 0; } .container-fluid { box-sizing: border-box; margin: 0; padding: 5px; } .crud-toolbar { display: flex; align-items: flex-end; gap: 10px 14px; min-height: 54px; margin-bottom: 6px; padding: 6px 9px; border: 1px solid #dbe2ea; background: #f8fafc; } .selection-summary { display: flex; flex-direction: column; min-width: 0; } .selection-summary strong { display: flex; align-items: center; gap: 6px; color: #0f172a; font-size: 13px; } .selection-summary span { color: #64748b; font-size: 12px; } .crud-actions { display: flex; gap: 6px; } .crud-status { display: flex; flex-direction: column; min-width: 240px; color: #475569; font-size: 13px; line-height: 1.35; } .crud-actions { margin-left: auto; } .demo-selected-target { outline: 3px solid #0f6cbd !important; outline-offset: -3px; box-shadow: inset 0 0 0 1px #ffffff; } #operationStatus { color: #1f2937; font-weight: 600; } .form-select:focus, .btn:focus-visible { border-color: #0f6cbd; box-shadow: 0 0 0 2px rgb(15 108 189 / 22%); } #theScheduler { height: calc(100vh - 64px); min-height: 600px; } @media (max-width: 700px) { .crud-toolbar { align-items: stretch; flex-wrap: wrap; } .selection-summary { flex: 1 1 100%; } .crud-actions { margin-left: 0; flex: 0 0 auto; } .crud-status { flex: 1 1 180px; min-width: 0; } #theScheduler { height: 680px; min-height: 680px; } } input, textarea, [contenteditable="true"] { user-select: text; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true, }, meta: { '*.css': { loader: 'css' }, }, paths: { // paths serve as alias 'npm:': 'node_modules/', 'cdn:': 'https://cdn.mescius.io/demoapps/packages/wijmojs/5.20262.60-rc/', 'pcdn:': 'https://cdn.jsdelivr.net/npm/', }, // map tells the System loader where to look for things map: { '@mescius/wijmo': 'cdn:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'cdn:@mescius/wijmo.input/index.js', '@mescius/wijmo.scheduler': 'cdn:@mescius/wijmo.scheduler/index.js', '@mescius/wijmo.styles': 'cdn:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'cdn:@mescius/wijmo.cultures', jszip: 'pcdn:jszip@3.8.0/dist/jszip.js', 'bootstrap.css': 'pcdn:bootstrap@5.3.8/dist/css/bootstrap.min.css', css: 'pcdn:systemjs-plugin-css@0.1.37/css.js', 'plugin-babel': 'pcdn:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'pcdn:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', }, packages: { src: { defaultExtension: 'js', }, node_modules: { defaultExtension: 'js', }, }, }); })(this);