DevExtreme v23.1 is now available.

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

Your search did not match any results.
Scheduler

Context Menu Integration

Documentation

This demo shows how to create a context menu for appointments and cells using the onAppointmentContextMenu and onCellContextMenu functions.

Backend API
Copy to CodePen
Apply
Reset
const DemoApp = angular.module('DemoApp', ['dx']); const appointmentClassName = '.dx-scheduler-appointment'; const cellClassName = '.dx-scheduler-date-table-cell'; DemoApp.controller('DemoController', ($scope) => { $scope.groups = undefined; $scope.crossScrolling = false; $scope.currentDate = new Date(2020, 10, 25); $scope.dataSource = []; $scope.disabled = true; $scope.target = appointmentClassName; $scope.itemTemplate = undefined; $scope.onItemClick = undefined; $scope.contextMenuOptions = { width: 200, bindingOptions: { dataSource: 'dataSource', disabled: 'disabled', target: 'target', itemTemplate: 'itemTemplate', onItemClick: 'onItemClick', }, }; $scope.schedulerOptions = { timeZone: 'America/Los_Angeles', bindingOptions: { groups: 'groups', crossScrollingEnabled: 'crossScrolling', currentDate: 'currentDate', }, dataSource: data, views: ['day', 'month'], currentView: 'month', startDayHour: 9, recurrenceEditMode: 'series', onAppointmentContextMenu(e) { $scope.target = appointmentClassName; $scope.disabled = false; $scope.dataSource = appointmentContextMenuItems; $scope.itemTemplate = 'item-template'; $scope.onItemClick = onItemClick(e); }, onCellContextMenu(e) { $scope.target = cellClassName; $scope.disabled = false; $scope.dataSource = cellContextMenuItems; $scope.itemTemplate = 'item'; $scope.onItemClick = onItemClick(e); }, resources: [{ fieldExpr: 'roomId', dataSource: resourcesData, label: 'Room', }], height: 600, }; const onItemClick = function (contextMenuEvent) { return function (e) { e.itemData.onItemClick(contextMenuEvent, e); }; }; const createAppointment = function (e) { e.component.showAppointmentPopup({ startDate: e.cellData.startDate, }, true); }; const createRecurringAppointment = function (e) { e.component.showAppointmentPopup({ startDate: e.cellData.startDate, recurrenceRule: 'FREQ=DAILY', }, true); }; const groupCell = function () { if ($scope.groups && $scope.groups.length) { $scope.crossScrolling = false; $scope.groups = undefined; } else { $scope.crossScrolling = true; $scope.groups = ['roomId']; } }; const showCurrentDate = function () { $scope.currentDate = new Date(); }; const showAppointment = function (e) { e.component.showAppointmentPopup(e.appointmentData); }; const deleteAppointment = function (e) { e.component.deleteAppointment(e.appointmentData); }; const repeatAppointmentWeekly = function (e) { const itemData = e.appointmentData; e.component.updateAppointment(itemData, $.extend(itemData, { startDate: e.targetedAppointmentData.startDate, recurrenceRule: 'FREQ=WEEKLY', })); }; const setResource = function (e, clickEvent) { const itemData = e.appointmentData; e.component.updateAppointment(itemData, $.extend(itemData, { roomId: [clickEvent.itemData.id], })); }; const cellContextMenuItems = [ { text: 'New Appointment', onItemClick: createAppointment }, { text: 'New Recurring Appointment', onItemClick: createRecurringAppointment }, { text: 'Group by Room/Ungroup', beginGroup: true, onItemClick: groupCell }, { text: 'Go to Today', onItemClick: showCurrentDate }, ]; let appointmentContextMenuItems = [ { text: 'Open', onItemClick: showAppointment }, { text: 'Delete', onItemClick: deleteAppointment }, { text: 'Repeat Weekly', beginGroup: true, onItemClick: repeatAppointmentWeekly }, { text: 'Set Room', beginGroup: true, disabled: true }, ]; $.each(resourcesData, (i, item) => { item.onItemClick = setResource; }); appointmentContextMenuItems = $.merge(appointmentContextMenuItems, resourcesData); });
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <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=1.0" /> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script>window.jQuery || document.write(decodeURIComponent('%3Cscript src="js/jquery.min.js"%3E%3C/script%3E'))</script> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/23.1.5/css/dx.light.css" /> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script> <script>window.angular || document.write(decodeURIComponent('%3Cscript src="js/angular.min.js"%3E%3C/script%3E'))</script> <script src="https://cdn3.devexpress.com/jslib/23.1.5/js/dx.all.js"></script> <script src="data.js"></script> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="index.js"></script> </head> <body class="dx-viewport"> <div class="demo-container" ng-app="DemoApp" ng-controller="DemoController"> <div id="scheduler" dx-scheduler="schedulerOptions"></div> <div id="context-menu" dx-context-menu="contextMenuOptions" dx-item-alias="item"> <div data-options="dxTemplate: {name: 'item-template'} "> <div ng-if="item.color"> <div class="item-badge" ng-style="{ backgroundColor: item.color}"></div> </div> <div class="item-text">{{item.text}}</div> </div> </div> </div> </body> </html>
.dx-menu-item-content span { margin-right: 5px; } .dx-menu-item-has-submenu .dx-icon-spinright { position: absolute; top: 7px; right: 2px; } .item-badge { text-align: center; float: left; margin-right: 12px; color: white; width: 18px; height: 18px; font-size: 19.5px; border-radius: 18px; margin-top: 2px; }
const data = [ { text: 'Watercolor Landscape', roomId: [1], startDate: new Date('2020-11-01T17:30:00.000Z'), endDate: new Date('2020-11-01T19:00:00.000Z'), recurrenceRule: 'FREQ=WEEKLY;BYDAY=MO,TH;COUNT=10', }, { text: 'Oil Painting for Beginners', roomId: [2], startDate: new Date('2020-11-01T17:30:00.000Z'), endDate: new Date('2020-11-01T19:00:00.000Z'), recurrenceRule: 'FREQ=WEEKLY;BYDAY=SU,WE;COUNT=10', }, { text: 'Testing', roomId: [3], startDate: new Date('2020-11-01T20:00:00.000Z'), endDate: new Date('2020-11-01T21:00:00.000Z'), recurrenceRule: 'FREQ=WEEKLY;BYDAY=SU;WKST=TU;INTERVAL=2;COUNT=2', }, { text: 'Meeting of Instructors', roomId: [4], startDate: new Date('2020-11-01T17:00:00.000Z'), endDate: new Date('2020-11-01T17:15:00.000Z'), recurrenceRule: 'FREQ=DAILY;BYDAY=TU;UNTIL=20201203', }, { text: 'Recruiting students', roomId: [5], startDate: new Date('2020-10-24T18:00:00.000Z'), endDate: new Date('2020-10-24T19:00:00.000Z'), recurrenceRule: 'FREQ=YEARLY;BYWEEKNO=50;WKST=SU', recurrenceException: '20201212T190000Z', }, { text: 'Final exams', roomId: [3], startDate: new Date('2020-10-24T20:00:00.000Z'), endDate: new Date('2020-10-24T21:35:00.000Z'), recurrenceRule: 'FREQ=YEARLY;BYWEEKNO=51;BYDAY=WE,TH', }, { text: 'Monthly Planning', roomId: [4], startDate: new Date('2020-11-24T22:30:00.000Z'), endDate: new Date('2020-11-24T23:45:00.000Z'), recurrenceRule: 'FREQ=MONTHLY;BYMONTHDAY=28;COUNT=1', }, { text: 'Open Day', roomId: [5], startDate: new Date('2020-11-01T17:30:00.000Z'), endDate: new Date('2020-11-01T21:00:00.000Z'), recurrenceRule: 'FREQ=YEARLY;BYYEARDAY=333', }, ]; const resourcesData = [ { text: 'Room 101', id: 1, color: '#bbd806', }, { text: 'Room 102', id: 2, color: '#f34c8a', }, { text: 'Room 103', id: 3, color: '#ae7fcc', }, { text: 'Meeting room', id: 4, color: '#ff8817', }, { text: 'Conference hall', id: 5, color: '#03bb92', }, ];