DevExtreme v25.1 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

Angular Scheduler - Toolbar

The DevExtreme Scheduler ships with a customizable toolbar UI element. You can populate the toolbar with predefined and custom items—in any display order. This demo adds the "today" predefined control and two DevExtreme components to the toolbar.

Backend API
<dx-scheduler timeZone="America/Los_Angeles" [dataSource]="dataSource" [views]="['day', 'week', 'workWeek', 'month']" currentView="workWeek" [currentDate]="currentDate" [startDayHour]="9" [endDayHour]="19" [height]="600" > <dxi-scheduler-resource fieldExpr="assigneeId" label="Assignee" [allowMultiple]="true" [dataSource]="assignees" > </dxi-scheduler-resource> <dxo-scheduler-toolbar> <dxi-scheduler-toolbar-item location="before" name="today" ></dxi-scheduler-toolbar-item> <dxi-scheduler-toolbar-item location="before" name="dateNavigator" ></dxi-scheduler-toolbar-item> <dxi-scheduler-toolbar-item location="before" locateInMenu="auto" widget="dxButton" [options]="newEventButtonOptions" > </dxi-scheduler-toolbar-item> <dxi-scheduler-toolbar-item location="before" locateInMenu="auto"> <div *dxTemplate> <dx-select-box placeholder="Select Employee" [items]="assignees" [showClearButton]="true" displayExpr="text" valueExpr="id" [inputAttr]="{ 'aria-label': 'Select Employee' }" [width]="200" (onValueChanged)="onAssigneesChange($event)" > </dx-select-box> </div> </dxi-scheduler-toolbar-item> <dxi-scheduler-toolbar-item location="after" locateInMenu="auto" name="viewSwitcher" ></dxi-scheduler-toolbar-item> </dxo-scheduler-toolbar> </dx-scheduler>
import { NgModule, Component, ViewChild, enableProdMode } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { DxTemplateModule } from 'devextreme-angular'; import { DxButtonModule, type DxButtonTypes } from 'devextreme-angular/ui/button'; import { DxSchedulerModule, DxSchedulerComponent } from 'devextreme-angular/ui/scheduler'; import { DxSelectBoxModule, type DxSelectBoxTypes } from 'devextreme-angular/ui/select-box'; import { Service } from './app.service'; const MS_IN_HOUR = 60 * 1000; if (!/localhost/.test(document.location.host)) { enableProdMode(); } let modulePrefix = ''; // @ts-ignore if (window && window.config?.packageConfigPaths) { modulePrefix = '/app'; } @Component({ styleUrls: [`app/app.component.css`], selector: 'demo-app', templateUrl: `app/app.component.html`, providers: [Service], }) export class AppComponent { @ViewChild(DxSchedulerComponent, { static: true }) scheduler: DxSchedulerComponent; dataSource = this.service.getAppointmentsDataSource(); assignees = this.service.getAssignees(); currentDate = this.service.getInitialCurrentDate(); newEventButtonOptions: DxButtonTypes.Properties = { icon: 'plus', text: 'New Appointment', stylingMode: 'outlined', type: 'normal', onClick: () => { this.onAppointmentAdd(); }, }; constructor(private service: Service) {} onAppointmentAdd() { const selected = this.scheduler.instance.option('selectedCellData') ?? []; if (selected.length) { const firstSelected = selected[0]; const lastSelected = selected.at(-1); this.scheduler.instance.showAppointmentPopup({ ...firstSelected.groups, allDay: firstSelected.allDay, startDate: new Date(firstSelected.startDateUTC), endDate: new Date(lastSelected.endDateUTC), }, true); return; } const currentDate = this.scheduler.instance.option('currentDate'); const cellDuration = this.scheduler.instance.option('cellDuration') as number; const cellDurationMs = cellDuration * MS_IN_HOUR; const currentTime = new Date(currentDate as Date).getTime(); const roundTime = Math.round(currentTime / cellDurationMs) * cellDurationMs; this.scheduler.instance.showAppointmentPopup({ startDate: new Date(roundTime), endDate: new Date(roundTime + cellDurationMs), }, true); } onAssigneesChange(event: DxSelectBoxTypes.ValueChangedEvent) { const dataSource = this.scheduler.instance.option('dataSource'); const filter = event.value ? ['assigneeId', 'contains', event.value] : null; dataSource.filter(filter); this.scheduler.instance.option('dataSource', dataSource); } } @NgModule({ imports: [ BrowserModule, DxTemplateModule, DxButtonModule, DxSchedulerModule, DxSelectBoxModule, ], declarations: [AppComponent], bootstrap: [AppComponent], }) export class AppModule { } platformBrowserDynamic().bootstrapModule(AppModule);
import { Injectable } from '@angular/core'; import { DataSource } from 'devextreme-angular/common/data'; export interface Appointment { text: string; startDate: number; endDate: number; allDay?: boolean; assigneeId: number[]; recurrenceRule?: string; } export interface Assignee { id: number; text: string; } const ONE_MONTH_DAYS = 30; const addDays = (date, days) => new Date(new Date(date).setUTCDate(date.getUTCDate() + days)); const now = new Date(new Date().setUTCHours(0, 0, 0, 0)); const startOfTheWeek = addDays(now, -now.getUTCDay()); const currentDate = addDays(now, ONE_MONTH_DAYS); const currentStartOfTheWeek = addDays(currentDate, -currentDate.getUTCDay()); const appointments: Appointment[] = [ { text: 'Website Re-Design Plan', assigneeId: [4], startDate: addDays(startOfTheWeek, 1).setUTCHours(16, 30), endDate: addDays(startOfTheWeek, 1).setUTCHours(18, 30), }, { text: 'Book Flights to San Fran for Sales Trip', assigneeId: [2], startDate: addDays(startOfTheWeek, 2).setUTCHours(19), endDate: addDays(startOfTheWeek, 2).setUTCHours(20), allDay: true, }, { text: 'Install New Router in Dev Room', assigneeId: [1], startDate: addDays(startOfTheWeek, 2).setUTCHours(21, 30), endDate: addDays(startOfTheWeek, 2).setUTCHours(22, 30), }, { text: 'Approve Personal Computer Upgrade Plan', assigneeId: [3], startDate: addDays(startOfTheWeek, 3).setUTCHours(17), endDate: addDays(startOfTheWeek, 3).setUTCHours(18), }, { text: 'Final Budget Review', assigneeId: [1], startDate: addDays(startOfTheWeek, 3).setUTCHours(19), endDate: addDays(startOfTheWeek, 3).setUTCHours(20, 35), }, { text: 'New Brochures', assigneeId: [4], startDate: addDays(startOfTheWeek, 3).setUTCHours(21, 30), endDate: addDays(startOfTheWeek, 3).setUTCHours(22, 45), }, { text: 'Install New Database', assigneeId: [2], startDate: addDays(startOfTheWeek, 4).setUTCHours(16, 45), endDate: addDays(startOfTheWeek, 4).setUTCHours(18, 15), }, { text: 'Approve New Online Marketing Strategy', assigneeId: [4], startDate: addDays(currentStartOfTheWeek, 1).setUTCHours(19), endDate: addDays(currentStartOfTheWeek, 1).setUTCHours(21), }, { text: 'Upgrade Personal Computers', assigneeId: [2], startDate: addDays(currentStartOfTheWeek, 1).setUTCHours(22, 15), endDate: addDays(currentStartOfTheWeek, 1).setUTCHours(23, 30), }, { text: 'Customer Workshop', assigneeId: [3], startDate: addDays(startOfTheWeek, 5).setUTCHours(18), endDate: addDays(startOfTheWeek, 5).setUTCHours(19), recurrenceRule: 'FREQ=WEEKLY;INTERVAL=1', }, { text: 'Prepare 2021 Marketing Plan', assigneeId: [1], startDate: addDays(currentStartOfTheWeek, 2).setUTCHours(18), endDate: addDays(currentStartOfTheWeek, 2).setUTCHours(20, 30), }, { text: 'Brochure Design Review', assigneeId: [4], startDate: addDays(startOfTheWeek, 5).setUTCHours(21), endDate: addDays(startOfTheWeek, 5).setUTCHours(22, 30), }, { text: 'Create Icons for Website', assigneeId: [3], startDate: addDays(currentStartOfTheWeek, 3).setUTCHours(17), endDate: addDays(currentStartOfTheWeek, 3).setUTCHours(18, 30), }, { text: 'Upgrade Server Hardware', assigneeId: [4], startDate: addDays(currentStartOfTheWeek, 2).setUTCHours(16), endDate: addDays(currentStartOfTheWeek, 2).setUTCHours(17, 30), }, { text: 'Submit New Website Design', assigneeId: [1], startDate: addDays(currentStartOfTheWeek, 5).setUTCHours(23, 30), endDate: addDays(currentStartOfTheWeek, 6).setUTCHours(1), }, { text: 'Launch New Website', assigneeId: [2], startDate: addDays(currentStartOfTheWeek, 4).setUTCHours(19), endDate: addDays(currentStartOfTheWeek, 4).setUTCHours(21), }, ]; const assignees: Assignee[] = [ { text: 'Samantha Bright', id: 1, }, { text: 'John Heart', id: 2, }, { text: 'Todd Hoffman', id: 3, }, { text: 'Sandra Johnson', id: 4, }, ]; @Injectable() export class Service { getAppointmentsDataSource(): DataSource { return new DataSource(appointments); } getAssignees(): Assignee[] { return assignees; } getInitialCurrentDate(): Date { return currentDate; } }
// In real applications, you should not transpile code in the browser. // You can see how to create your own application with Angular and DevExtreme here: // https://js.devexpress.com/Documentation/Guide/Angular_Components/Getting_Started/Create_a_DevExtreme_Application/ const componentNames = [ 'accordion', 'action-sheet', 'autocomplete', 'bar-gauge', 'box', 'bullet', 'button-group', 'button', 'calendar', 'card-view', 'chart', 'chat', 'check-box', 'circular-gauge', 'color-box', 'context-menu', 'data-grid', 'date-box', 'date-range-box', 'defer-rendering', 'diagram', 'draggable', 'drawer', 'drop-down-box', 'drop-down-button', 'file-manager', 'file-uploader', 'filter-builder', 'form', 'funnel', 'gallery', 'gantt', 'html-editor', 'linear-gauge', 'list', 'load-indicator', 'load-panel', 'lookup', 'map', 'menu', 'multi-view', 'nested', 'number-box', 'pagination', 'pie-chart', 'pivot-grid-field-chooser', 'pivot-grid', 'polar-chart', 'popover', 'popup', 'progress-bar', 'radio-group', 'range-selector', 'range-slider', 'recurrence-editor', 'resizable', 'responsive-box', 'sankey', 'scheduler', 'scroll-view', 'select-box', 'slider', 'sortable', 'sparkline', 'speed-dial-action', 'splitter', 'stepper', 'switch', 'tab-panel', 'tabs', 'tag-box', 'text-area', 'text-box', 'tile-view', 'toast', 'toolbar', 'tooltip', 'tree-list', 'tree-map', 'tree-view', 'validation-group', 'validation-summary', 'validator', 'vector-map', ]; window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, }, meta: { 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, '@angular/platform-browser-dynamic': { 'esModule': true, }, '@angular/platform-browser': { 'esModule': true, }, '@angular/core': { 'esModule': true, }, '@angular/common': { 'esModule': true, }, '@angular/common/http': { 'esModule': true, }, '@angular/animations': { 'esModule': true, }, '@angular/forms': { 'esModule': true, }, 'openai': { 'esModule': true, }, }, paths: { 'npm:': 'https://cdn.jsdelivr.net/npm/', 'bundles:': '../../../../bundles/', 'externals:': '../../../../bundles/externals/', }, map: { 'ts': 'npm:plugin-typescript@8.0.0/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', /* @angular */ '@angular/compiler': 'bundles:@angular/compiler.umd.js', '@angular/platform-browser-dynamic': 'bundles:@angular/platform-browser-dynamic.umd.js', '@angular/core': 'bundles:@angular/core.umd.js', '@angular/core/primitives/signals': 'bundles:@angular/core.primitives.signals.umd.js', '@angular/common': 'bundles:@angular/common.umd.js', '@angular/common/http': 'bundles:@angular/common-http.umd.js', '@angular/platform-browser': 'bundles:@angular/platform-browser.umd.js', '@angular/platform-browser/animations': 'bundles:@angular/platform-browser.umd.js', '@angular/forms': 'bundles:@angular/forms.umd.js', /* devextreme */ 'devextreme': 'npm:devextreme@25.1.3/cjs', 'devextreme-quill': 'npm:devextreme-quill@1.7.3/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.19', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.62', /* devextreme-angular umd maps */ 'devextreme-angular': 'bundles:devextreme-angular/devextreme-angular.umd.js', 'devextreme-angular/common/ai-integration': 'bundles:devextreme-angular/devextreme-angular-common-ai-integration.umd.js', 'devextreme-angular/core': 'bundles:devextreme-angular/devextreme-angular-core.umd.js', 'devextreme-angular/common/charts': 'bundles:devextreme-angular/devextreme-angular-common-charts.umd.js', 'devextreme-angular/common/core/animation': 'bundles:devextreme-angular/devextreme-angular-common-core-animation.umd.js', 'devextreme-angular/common/core/environment': 'bundles:devextreme-angular/devextreme-angular-common-core-environment.umd.js', 'devextreme-angular/common/core/events': 'bundles:devextreme-angular/devextreme-angular-common-core-events.umd.js', 'devextreme-angular/common/core/localization': 'bundles:devextreme-angular/devextreme-angular-common-core-localization.umd.js', 'devextreme-angular/common/core': 'bundles:devextreme-angular/devextreme-angular-common-core.umd.js', 'devextreme-angular/common/data/custom-store': 'bundles:devextreme-angular/devextreme-angular-common-data-custom-store.umd.js', 'devextreme-angular/common/data': 'bundles:devextreme-angular/devextreme-angular-common-data.umd.js', 'devextreme-angular/common/export/excel': 'bundles:devextreme-angular/devextreme-angular-common-export-excel.umd.js', 'devextreme-angular/common/export/pdf': 'bundles:devextreme-angular/devextreme-angular-common-export-pdf.umd.js', 'devextreme-angular/common/export': 'bundles:devextreme-angular/devextreme-angular-common-export.umd.js', 'devextreme-angular/common/grids': 'bundles:devextreme-angular/devextreme-angular-common-grids.umd.js', 'devextreme-angular/common': 'bundles:devextreme-angular/devextreme-angular-common.umd.js', 'devextreme-angular/http': 'bundles:devextreme-angular/devextreme-angular-http.umd.js', ...componentNames.reduce((acc, name) => { acc[`devextreme-angular/ui/${name}`] = `bundles:devextreme-angular/devextreme-angular-ui-${name}.umd.js`; acc[`devextreme-angular/ui/${name}/nested`] = `bundles:devextreme-angular/devextreme-angular-ui-${name}-nested.umd.js`; return acc; }, {}), 'tslib': 'npm:tslib/tslib.js', 'rxjs': 'npm:rxjs@7.5.3/dist/bundles/rxjs.umd.js', 'rxjs/operators': 'npm:rxjs@7.5.3/dist/cjs/operators/index.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign', 'inferno': 'npm:inferno@8.2.3/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@8.2.3/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', '@preact/signals-core': 'npm:@preact/signals-core@1.8.0/dist/signals-core.min.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'app': { main: './app.component.ts', defaultExtension: 'ts', }, 'devextreme': { defaultExtension: 'js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/common/core/events/utils': { main: 'index', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, 'rxjs': { defaultExtension: 'js', }, 'rxjs/operators': { defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:rxjs@7.5.3/package.json', 'npm:rxjs@7.5.3/operators/package.json', 'npm:devexpress-diagram@2.2.19/package.json', 'npm:devexpress-gantt@4.1.62/package.json', ], }; System.config(window.config); // System.import('@angular/compiler').catch(console.error.bind(console));
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/25.1.3/css/dx.light.css" /> <script src="https://cdn.jsdelivr.net/npm/core-js@2.6.12/client/shim.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/zone.js@0.14.10/bundles/zone.umd.js"></script> <script src="https://cdn.jsdelivr.net/npm/reflect-metadata@0.1.13/Reflect.js"></script> <script src="https://cdn.jsdelivr.net/npm/systemjs@0.21.3/dist/system.js"></script> <script src="config.js"></script> <script> System.import("app").catch(console.error.bind(console)); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <demo-app>Loading...</demo-app> </div> </body> </html>

To customize the Scheduler toolbar in your DevExtreme-powered app, add items to the toolbar.items[] array. DevExtreme Scheduler supports the following toolbar item types:

  • Predefined Controls

    • "dateNavigator"
      Displays a ButtonGroup component with next/previous buttons and a date interval button that invokes a dropdown calendar. Define options.items to customize the control. You can add new buttons, and specify button availability/order.
    • "viewSwitcher"
      Switches between view types (day, week, month, and others).
    • "today"
      A "Today" button (navigates to the current date).
  • DevExtreme Components
    You can configure a DevExtreme component within a toolbar item element. In this demo, we extended the toolbar with a Button and SelectBox.

  • Custom Controls
    Specify items[].template to implement custom controls.

The default Scheduler toolbar displays "dateNavigator" and "viewSwitcher" predefined controls.