Scheduling / Planning ▸ Context Menu

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

@model DevExtreme.MVC.Demos.ViewModels.RecurringAppointmentsViewModel

@using DevExtreme.MVC.Demos.Models;

@(Html.DevExtreme().Scheduler()
    .ID("scheduler")
    .DataSource(Model.Appointments)
    .TimeZone("America/Los_Angeles")
    .Views(new[] { SchedulerViewType.Day, SchedulerViewType.Month })
    .CurrentView(SchedulerViewType.Month)
    .CurrentDate(new DateTime(2020, 11, 25))
    .RecurrenceEditMode(SchedulerRecurrenceEditMode.Series)
    .StartDayHour(9)
    .Groups(new JS("[]"))
    .Resources(res => { res.Add()
        .FieldExpr("RoomId")
        .ValueExpr("Id")
        .ColorExpr("Color")
        .DisplayExpr("Text")
        .Label("Room")
        .Icon("conferenceroomoutline")
        .DataSource(Model.Resources);
    })
    .OnCellContextMenu("onCellContextMenu")
    .OnAppointmentContextMenu("onAppointmentContextMenu")
    .Height(730)
    .TextExpr("Text")
    .StartDateExpr("StartDate")
    .EndDateExpr("EndDate")
    .RecurrenceRuleExpr("RecurrenceRule")
    .RecurrenceExceptionExpr("RecurrenceException")
)

@(Html.DevExtreme().ContextMenu()
    .ID("context-menu")
    .Target("#scheduler")
    .Width(200)
    .DataSource(new JS("[]"))
    .ItemTemplate(new JS("contextMenuItemTemplate"))
    .OnItemClick("onContextMenuItemClick")
    .OnHiding("onContextMenuHiding")
)

<script>
    const resourcesData = @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.Resources.Select(r => new { id = r.Id, text = r.Text, color = r.Color })));

    function onAppointmentContextMenu(e) {
        const items = getAppointmentContextMenuItems(e);
        const contextMenuInstance = $("#context-menu").dxContextMenu("instance");
        contextMenuInstance.option("dataSource", items);
    }

    function onCellContextMenu(e) {
        const items = getCellContextMenuItems(e);
        const contextMenuInstance = $("#context-menu").dxContextMenu("instance");
        contextMenuInstance.option("dataSource", items);
    }

    function onContextMenuItemClick(e) {
        e.itemData.onItemClick(e);
    }

    function onContextMenuHiding(e) {
        e.component.option("dataSource", []);
    }

    function contextMenuItemTemplate(itemData) {
        const template = $('<div></div>');

        if (itemData.color) {
            $('<div>')
                .addClass('item-badge')
                .css('background-color', itemData.color)
                .appendTo(template);
        }
        template.append(itemData.text);
        return template;
    }

    function getAppointmentContextMenuItems(e) {
        const scheduler = e.component;
        const appointment = e.appointmentData;
        const targetedAppointment = e.targetedAppointmentData;

        return [
            {
                text: 'Open',
                onItemClick: function() { scheduler.showAppointmentPopup(appointment); }
            },
            {
                text: 'Delete',
                onItemClick: function() { scheduler.deleteAppointment(appointment); }
            },
            {
                text: 'Repeat Weekly',
                beginGroup: true,
                onItemClick: function() {
                    scheduler.updateAppointment(appointment, $.extend(appointment, {
                        StartDate: targetedAppointment.StartDate,
                        RecurrenceRule: 'FREQ=WEEKLY'
                    }));
                }
            },
            {
                text: 'Set Room',
                beginGroup: true,
                disabled: true
            }
        ].concat(
            resourcesData.map(function(item) {
                return {
                    ...item,
                    onItemClick: function(clickEvent) {
                        scheduler.updateAppointment(appointment, $.extend(appointment, {
                            RoomId: [clickEvent.itemData.id]
                        }));
                    }
                };
            })
        );
    }

    function getCellContextMenuItems(e) {
        const scheduler = e.component;

        return [
            {
                text: 'New Appointment',
                onItemClick: function() {
                    scheduler.showAppointmentPopup({
                        StartDate: e.cellData.startDate
                    }, true);
                }
            },
            {
                text: 'New Recurring Appointment',
                onItemClick: function() {
                    scheduler.showAppointmentPopup({
                        StartDate: e.cellData.startDate,
                        RecurrenceRule: 'FREQ=DAILY'
                    }, true);
                }
            },
            {
                text: 'Group by Room/Ungroup',
                beginGroup: true,
                onItemClick: function() {
                    if (scheduler.option('groups').length) {
                        scheduler.option({ crossScrollingEnabled: false, groups: [] });
                    } else {
                        scheduler.option({ crossScrollingEnabled: true, groups: ['RoomId'] });
                    }
                }
            },
            {
                text: 'Go to Today',
                onItemClick: function() {
                    scheduler.option('currentDate', new Date());
                }
            }
        ];
    }
</script>
using DevExtreme.MVC.Demos.Models.SampleData;
using DevExtreme.MVC.Demos.ViewModels;

using System.Web.Mvc;

namespace DevExtreme.MVC.Demos.Controllers {
    public class SchedulerController : Controller {

        public ActionResult ContextMenu() {
            return View(new RecurringAppointmentsViewModel {
                Appointments = SampleData.RecurringAppointments,
                Resources = SampleData.RecurringAppointmentsResources
            });
        }

    }
}
using System;
using System.Collections.Generic;
using System.Linq;

namespace DevExtreme.MVC.Demos.Models {
    public class RecurringAppointment : Appointment {
        public int RoomId { get; set; }
    }
}
using System;
using System.Collections.Generic;

namespace DevExtreme.MVC.Demos.Models.SampleData {
    public partial class SampleData {
        public static readonly IEnumerable<RecurringAppointment> RecurringAppointments = new[] {
            new RecurringAppointment {
                Text = "Watercolor Landscape",
                RoomId = 1,
                StartDate = "2020-11-01T17:30:00.000Z",
                EndDate = "2020-11-01T19:00:00.000Z",
                RecurrenceRule = "FREQ=WEEKLY;BYDAY=MO,TH;COUNT=10"
            },
            new RecurringAppointment {
                Text = "Oil Painting for Beginners",
                RoomId = 2,
                StartDate = "2020-11-01T17:30:00.000Z",
                EndDate = "2020-11-01T19:00:00.000Z",
                RecurrenceRule = "FREQ=WEEKLY;BYDAY=SU,WE;COUNT=10"
            },
            new RecurringAppointment {
                Text = "Testing",
                RoomId = 3,
                StartDate = "2020-11-01T20:00:00.000Z",
                EndDate = "2020-11-01T21:00:00.000Z",
                RecurrenceRule = "FREQ=WEEKLY;BYDAY=SU;WKST=TU;INTERVAL=2;COUNT=2"
            },
            new RecurringAppointment {
                Text = "Meeting of Instructors",
                RoomId = 4,
                StartDate = "2020-11-01T17:00:00.000Z",
                EndDate = "2020-11-01T17:15:00.000Z",
                RecurrenceRule = "FREQ=DAILY;BYDAY=TU;UNTIL=20201203"
            },
            new RecurringAppointment {
                Text = "Recruiting students",
                RoomId = 5,
                StartDate = "2020-10-24T18:00:00.000Z",
                EndDate = "2020-10-24T19:00:00.000Z",
                RecurrenceRule = "FREQ=YEARLY;BYWEEKNO=50;WKST=SU",
                RecurrenceException = "20201212T190000Z"
            },
            new RecurringAppointment {
                Text = "Final exams",
                RoomId = 3,
                StartDate = "2020-10-24T20:00:00.000Z",
                EndDate = "2020-10-24T21:35:00.000Z",
                RecurrenceRule = "FREQ=YEARLY;BYWEEKNO=51;BYDAY=WE,TH"
            },
            new RecurringAppointment {
                Text = "Monthly Planning",
                RoomId = 4,
                StartDate = "2020-11-24T22:30:00.000Z",
                EndDate = "2020-11-24T23:45:00.000Z",
                RecurrenceRule = "FREQ=MONTHLY;BYMONTHDAY=28;COUNT=1"
            },
            new RecurringAppointment {
                Text = "Open Day",
                RoomId = 5,
                StartDate = "2020-11-01T17:30:00.000Z",
                EndDate = "2020-11-01T21:00:00.000Z",
                RecurrenceRule = "FREQ=YEARLY;BYYEARDAY=333"
            }
        };
    }
}
using System;
using System.Collections.Generic;
using System.Linq;

namespace DevExtreme.MVC.Demos.Models {
    public class RecurringAppointmentsResource {
        public int Id { get; set; }
        public string Text { get; set; }
        public string Color { get; set; }
    }
}
using System;
using System.Collections.Generic;

namespace DevExtreme.MVC.Demos.Models.SampleData {
    public partial class SampleData {
        public static readonly IEnumerable<RecurringAppointmentsResource> RecurringAppointmentsResources = new[] {
            new RecurringAppointmentsResource {
                Id = 1,
                Text = "Room 101",
                Color = "#bbd806"
            },
            new RecurringAppointmentsResource {
                Id = 2,
                Text = "Room 102",
                Color = "#f34c8a"
            },
            new RecurringAppointmentsResource {
                Id = 3,
                Text = "Room 103",
                Color = "#ae7fcc"
            },
            new RecurringAppointmentsResource {
                Id = 4,
                Text = "Meeting room",
                Color = "#ff8817"
            },
            new RecurringAppointmentsResource {
                Id = 5,
                Text = "Conference hall",
                Color = "#03bb92"
            }
        };
    }
}
.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;
}