---
title: "Javascript Scheduler Bulk Event Actions Example | Mobiscroll"
component: "Scheduler"
framework: "JavaScript"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/javascript/scheduler/event-bulk-actions-edit-delete-update"
---

# Bulk Event Actions - JavaScript Scheduler demo

Add bulk event actions to Javascript Scheduler — select multiple events via shortcuts or select-all, apply bulk actions, and use right-click for per-event actions. Plain JavaScript API.

- [Live demo](https://demo.mobiscroll.com/javascript/scheduler/event-bulk-actions-edit-delete-update)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-javascript/tree/main/src/demos/eventcalendar/scheduler/event-bulk-actions-edit-delete-update)
- This demo in other frameworks: [jQuery](https://demo.mobiscroll.com/jquery/scheduler/event-bulk-actions-edit-delete-update.md), [Angular](https://demo.mobiscroll.com/angular/scheduler/event-bulk-actions-edit-delete-update.md), [React](https://demo.mobiscroll.com/react/scheduler/event-bulk-actions-edit-delete-update.md), [Vue](https://demo.mobiscroll.com/vue/scheduler/event-bulk-actions-edit-delete-update.md)

## Description

Multiple event selection can be turned on with the [`selectMultipleEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-selectMultipleEvents) option. Selecting multiple events can be done through user interaction with `CTRL`/`SHIFT`/`CMD` + click or programmatically eg. click of a button or 'select all' checkbox.

Bulk operations like delete, update can be applied the selected events. Things like deleting with the `backspace` or `delete` buttons work out of the box but custom actions can be also applied. The selection can be easily retrieved and updated with the [`getSelectedEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-getSelectedEvents) and [`setSelectedEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-setSelectedEvents) method.

Custom actions can be performed with external buttons or with context menu activated on right-click.

## What this demo shows

- A desktop weekly scheduler layout with a fixed week strip at the top, a fixed all-day row below it, and a scrollable scheduler time grid for the selected week.
- **Header navigation** The month and year label in the top left opens date navigation, while the blue previous and next arrows and the Today button on the right make it easy to move between weeks and jump back to the current day.
- **Week view** The fixed strip below the header displays the days of the selected week, with the current date highlighted by a blue circle.
- **All-day events** All-day events appear in a dedicated row that stays fixed above the time grid.
- **Time grid** The scheduler grid scrolls vertically through the hours of the selected week.
- **Bulk action panel** A side panel next to the scheduler contains `Select all from view`, `Reset selection`, and `Update selected` actions.
- **Select all from view** Clicking this action selects all events currently visible and highlights thei titles in the week view and shows a bottom-centered toast message: `All events selected from the view`.
- **Reset selection** Clicking this action clears the current selection and shows a bottom-centered toast message: `Selection cleared`.
- **Update selected** Clicking this action changes the color of all selected events to orange and shows a bottom-centered toast message: `All selected event's color changed to orange`.
- **Currently selected** The side panel includes a `Currently selected` section that is empty by default and lists the titles of all selected events when one or more events are selected.
- **Multi-selection** Users can select multiple events with `CTRL`/`SHIFT`/`CMD` + click.
- **Context menu** Right-clicking an event opens a small popup with `Update` and `Delete` actions for that event.
- **Timed events** Timed events are displayed in the weekly scheduler grid as colored cards with a colored stripe on the left, the event title in bold, and the exact start and end time displayed above the title.
- **Event overlapping** If events overlap, the scheduler places them side by side without hiding any of them or causing other conflicts.
- **Current time** A blue current-time line appears across the time grid, with a small blue dot marking the current date.
- **Hover behavior** Hovering over the time grid shows a time indicator that follows the cursor in 15-minute increments.
- **Event interaction** Hovering over events highlights them and shows drag and resize handles for repositioning or changing duration.
- **Event creation** Double-clicking the time grid or clicking and dragging on it creates a new event.

## Best for

- **Scheduling tools** Scheduling interfaces where users need to review and manage many visible events in a week view.
- **Resource management** Resource planning workflows that require selecting and adjusting multiple bookings, assignments, or availability blocks together.
- **Operations teams** Internal tools for managing appointments, team shifts, project deadlines, or other time-based records in batches.
- **Mixed individual and batch actions** Use cases that need both multi-event actions and single-event actions from a contextual right-click menu.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-themeVariant) - option
- [`getSelectedEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-getSelectedEvents) - method
- [`updateEvent`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-updateEvent) - method
- [`removeEvent`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-removeEvent) - method
- [`setSelectedEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-setSelectedEvents) - method
- [`addEvent`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-addEvent) - method
- [`clickToCreate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-dragToResize) - option
- [`eventDelete`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-eventDelete) - option
- [`selectMultipleEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-selectMultipleEvents) - option
- [`view`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-view) - option
- [`onEventUpdate`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventUpdate) - event
- [`onEventDelete`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventDelete) - event
- [`onPageLoading`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onPageLoading) - event
- [`onEventRightClick`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onEventRightClick) - event
- [`setOptions`](https://mobiscroll.com/docs/javascript/select/api#method-setOptions) - method
- [`anchor`](https://mobiscroll.com/docs/javascript/select/api#opt-anchor) - option
- [`open`](https://mobiscroll.com/docs/javascript/select/api#method-open) - method
- [`touchUi`](https://mobiscroll.com/docs/javascript/select/api#opt-touchUi) - option
- [`display`](https://mobiscroll.com/docs/javascript/select/api#opt-display) - option
- [`buttons`](https://mobiscroll.com/docs/javascript/select/api#opt-buttons) - option
- [`inputElement`](https://mobiscroll.com/docs/javascript/select/api#opt-inputElement) - option
- [`onChange`](https://mobiscroll.com/docs/javascript/select/api#event-onChange) - event
- [`onClose`](https://mobiscroll.com/docs/javascript/select/api#event-onClose) - event
- [`setVal`](https://mobiscroll.com/docs/javascript/select/api#method-setVal) - method
- [`getEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-getEvents) - method
- [`setEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-setEvents) - method

## Code

### JS

```js
mobiscroll.setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

var confirmOpen;
var firstDay;
var lastDay;
var selectedEvent;
var formatDate = mobiscroll.formatDate;
var listElm = document.createElement('ul');
document.getElementById('selected-event-list').append(listElm);

function getSelectedEventTitles(events) {
  var eventTitles = [];
  for (var i = 0; i < events.length; ++i) {
    eventTitles.push(events[i].title);
  }
  return eventTitles;
}

function deleteSelectedEvents() {
  var selectedEvents = calendar.getSelectedEvents();
  var events = selectedEvents.length == 0 && selectedEvent ? [selectedEvent] : selectedEvents;

  confirmOpen = true;

  mobiscroll.confirm({
    title: 'Are you sure you want to delete the following events?',
    message: getSelectedEventTitles(events).join(', '),
    okText: 'Delete',
    callback: function (result) {
      if (result) {
        var eventsToDelete = [];
        var eventsToUpdate = [];

        for (var i = 0; i < events.length; ++i) {
          var event = events[i];
          if (event.recurring) {
            var origEvent = event.original;
            var exc = origEvent.recurringException || [];
            exc.push(event.start);
            origEvent.recurringException = exc;
            eventsToUpdate.push(origEvent);
          } else {
            eventsToDelete.push(event);
          }
        }
        calendar.updateEvent(eventsToUpdate);
        calendar.removeEvent(eventsToDelete);
        calendar.setSelectedEvents([]);
        mobiscroll.toast({
          message: 'Deleted',
        });
      }
      confirmOpen = false;
    },
  });
}

function updateSelectedEvents() {
  var selectedEvents = calendar.getSelectedEvents();
  var events = selectedEvents.length == 0 && selectedEvent ? [selectedEvent] : selectedEvents;
  var eventsToUpdate = [];
  var newEvents = [];

  for (var i = 0; i < events.length; ++i) {
    var event = events[i];
    if (event.recurring) {
      var origEvent = event.original;
      var exc = origEvent.recurringException || [];
      var newEvent = event;

      newEvent.recurring = undefined;
      newEvent.color = 'orange';
      newEvent.id += '_' + formatDate('YYYY-MM-DD', event.start);
      newEvents.push(newEvent);

      exc.push(event.start);
      origEvent.recurringException = exc;
      eventsToUpdate.push(origEvent);
    } else {
      event.color = 'orange';
      eventsToUpdate.push(event);
    }
  }
  calendar.updateEvent(eventsToUpdate);
  calendar.addEvent(newEvents);
  calendar.setSelectedEvents([]);

  mobiscroll.toast({
    message: "All selected event's color changed to orange",
  });
}

var calendar = mobiscroll.eventcalendar('#demo-multiple-event-selection', {
  clickToCreate: true,
  dragToCreate: true,
  dragToMove: true,
  dragToResize: true,
  eventDelete: true,
  selectMultipleEvents: true,
  view: {
    scheduler: {
      type: 'week',
    },
  },
  onEventUpdate: function (args) {
    if (args.isDelete) {
      if (!confirmOpen) {
        deleteSelectedEvents();
      }
      return false;
    }
  },
  onEventDelete: function () {
    if (!confirmOpen) {
      deleteSelectedEvents();
      return false;
    }
  },
  onPageLoading: function (args) {
    firstDay = args.firstDay;
    lastDay = args.lastDay;
  },
  onEventRightClick: function (args) {
    selectedEvent = args.event;
    args.domEvent.preventDefault();
    menu.setOptions({
      anchor: args.domEvent.target,
    });
    setTimeout(function () {
      menu.open();
    });
  },
});

var menu = mobiscroll.select('#demo-context-menu', {
  touchUi: false,
  display: 'anchored',
  buttons: [],
  inputElement: document.getElementById('context-menu-input'),
  onChange: function (args) {
    if (args.value === 'update') {
      updateSelectedEvents();
    } else if (args.value === 'delete') {
      deleteSelectedEvents();
    }
  },
  onClose: function () {
    // Clear selection
    menu.setVal();
  },
});

document.getElementById('select-all-events').addEventListener('click', function () {
  calendar.setSelectedEvents(calendar.getEvents(firstDay, lastDay));
  mobiscroll.toast({
    message: 'All events selected from view',
  });
});

document.getElementById('reset-selection').addEventListener('click', function () {
  calendar.setSelectedEvents([]);
  mobiscroll.toast({
    message: 'Selection cleared',
  });
});

document.querySelector('.md-bulk-operations').addEventListener('keydown', function (ev) {
  if (!confirmOpen && (ev.keyCode === 8 || ev.keyCode === 46)) {
    deleteSelectedEvents();
  }
});

document.getElementById('update-selected').addEventListener('click', function () {
  updateSelectedEvents();
});

mobiscroll.getJson(
  'https://trial.mobiscroll.com/events/?vers=5',
  function (events) {
    calendar.setEvents(events);
  },
  'jsonp',
);
```

### HTML

```html
<div mbsc-page>
    <div class="mbsc-grid mbsc-no-padding">
        <div class="mbsc-row">
            <div class="mbsc-col-sm-9 mbsc-push-sm-3">
                <div id="demo-multiple-event-selection" class="md-bulk-operations"></div>
                <input id="context-menu-input" type="hidden" />
                <select id="demo-context-menu">
                    <option value="update">Update</option>
                    <option value="delete">Delete</option>
                </select>
            </div>
            <div class="mbsc-col-sm-3 mbsc-pull-sm-9">
                <div class="mbsc-form-group">
                    <div class="mbsc-button-group-block">
                        <button id="select-all-events" mbsc-button>Select all from view</button>
                        <button id="reset-selection" mbsc-button>Reset selection</button>
                        <button id="update-selected" mbsc-button>Update selected</button>
                    </div>
                </div>
                <div class="mbsc-form-group-title">Currently selected</div>
                <div id="selected-event-list" class="mbsc-padding md-selected-event-list"></div>
            </div>
        </div>
    </div>
</div>
```

### CSS

```css
.md-bulk-operations {
    border-left: 1px solid #ccc;
}

.md-selected-event-list {
    height: 500px;
    overflow: auto;
    padding-top: 0;
    padding-bottom: 0;
}
```

## Implementation notes

- Use `view: { scheduler: { type: 'week' } }`. Set `selectMultipleEvents: true` to enable Ctrl/Shift/Cmd+click multi-selection. Load events from `https://trial.mobiscroll.com/events/?vers=5` via JSONP. React/Angular/Vue: assign the fetched array to the state/property bound to the `data` prop. JS/jQuery (imperative API): call `inst.setEvents(events)` on load.
- Use a two-column layout: the calendar occupies most of the space; the sidebar contains three action buttons and a scrollable list of selected event titles. Button labels: React/Vue use "Select all this month"; Angular/JS/jQuery use "Select all from view"; all frameworks use "Reset selection" and "Update selected".
- Track `firstDay` and `lastDay` via `onPageLoading` (`args.firstDay`, `args.lastDay`). `onSelectedEventsChange` → update the current selection and refresh the displayed titles list.
- **"Select all"**: call `inst.getEvents(firstDay, lastDay)` to retrieve visible events, then set them as selected; for the imperative API, call `inst.setSelectedEvents(events)`. Show toast.
- **"Reset selection"**: clear `selectedEvents`; for the imperative API, call `inst.setSelectedEvents([])`. Show toast.
- **"Update selected"**: iterate the selected events. For **recurring occurrences**: clear `recurring`, set `color = 'orange'`, append `'_' + formatDate('YYYY-MM-DD', event.start)` to the `id`, push `event.start` to `origEvent.recurringException`, then persist the detached event and the updated original. For **non-recurring**: set `color = 'orange'` and update in place. Update the events array in place; for the imperative API, call `inst.updateEvent(eventsToUpdate)` and `inst.addEvent(newEvents)`. Reset selection, show toast.
- **`deleteSelectedEvents()`**: show a confirm dialog ("Are you sure you want to delete the following events?" / okText: "Delete") with selected event titles joined by `', '`. On confirm: for **recurring** events push `event.start` to `origEvent.recurringException` and update the original; for **non-recurring**, remove from the events array; for the imperative API, call `inst.removeEvent(eventsToDelete)` and `inst.setSelectedEvents([])`. Reset selection, show "Deleted" toast.
- **Delete entry points**: (1) **`onEventDelete`** - `return false` (all frameworks); (2) **`onEventUpdate` with `args.isDelete === true`** - `return false` (React/Angular/JS/jQuery; Vue omits `onEventUpdate`); (3) **context menu "Delete"**. Use a `confirmOpen` flag to prevent double-triggering from (1) and (2).
- **Right-click context menu**: `onEventRightClick` → `args.domEvent.preventDefault()`, open an anchored `Select` popup with "Update" / "Delete" options. Imperative API: also store `selectedEvent = args.event` as a fallback - used in `deleteSelectedEvents` and `updateSelectedEvents` when `inst.getSelectedEvents()` returns an empty array.
- **Keyboard delete**: attach a `keydown` listener on the container; if Delete or Backspace is pressed and no confirm dialog is open, call `deleteSelectedEvents()`.

## Run it in your project

1. If not signed up yet, or don't own a license, you can [start a free trial](https://mobiscroll.com/starttrial).

2. Clone the repository:

   ```
   git clone https://github.com/acidb/mobiscroll-demos-javascript.git
   ```

3. If not installed yet, install the Mobiscroll CLI from NPM:

   ```
   npm install -g @mobiscroll/cli
   ```

4. Config Mobiscroll - open a terminal window in the root directory and run:

   ```
   mobiscroll config javascript
   ```

5. Install dependencies - open a terminal window in the root directory and run:

   ```
   npm install
   ```

6. Run the project:

   ```
   npm run dev
   ```

On a trial, add `--trial` to the config command: `mobiscroll config javascript --trial`.

Running a demo locally requires a Mobiscroll trial or a license; setup is per framework at https://mobiscroll.com/docs/javascript/getting-started/installation

## Related demos

- Previous: [Create, Edit and Delete Events](https://demo.mobiscroll.com/javascript/scheduler/create-read-update-delete-CRUD.md) - Implement full event CRUD in a Javascript Scheduler — drag or click to create events, confirm via a custom dialog, then drag to move, resize, or delete.
- Next: [Recurring Event Add & Edit](https://demo.mobiscroll.com/javascript/scheduler/recurring-event-add-edit-dialog.md) - Add a recurrence editor to a Javascript Scheduler add/edit dialog — with daily, weekly, monthly, and custom presets plus an RRULE builder.
