Multi-Event Selection & Bulk Actions
Usage
theme: 'ios' You can turn auto theming on and let it decide based on the platform.
Usage
themeVariant: 'light' You can turn auto dark mode on based on system settings.
Usage
locale: localeEn Selecting the locale loads the localized settings and the translated UI text.
Multi-Event Selection & Bulk Actions
Multiple event selection can be turned on with the 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 selectedEvents option and the onSelectedEventsChange event.
Custom actions can be performed with external buttons or with context menu activated on right-click.
Demo

Code
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import {
formatDate,
MbscCalendarEvent,
MbscEventcalendar,
MbscEventcalendarOptions,
MbscModule,
MbscSelect,
MbscSelectOptions,
Notifications,
setOptions ,
} from '@mobiscroll/angular';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
providers: [Notifications],
standalone: true,
imports: [CommonModule, FormsModule, MbscModule],
})
export class AppComponent implements OnInit {
constructor(
private http: HttpClient,
private notify: Notifications,
) {}
@ViewChild('calendar', { static: false })
calendar!: MbscEventcalendar;
@ViewChild('menu', { static: false })
menu!: MbscSelect;
confirmOpen = false;
myEvents: MbscCalendarEvent[] = [];
selectedEvent?: MbscCalendarEvent;
selectedEvents: MbscCalendarEvent[] = [];
menuAction: string | null = null;
menuAnchor!: HTMLElement;
calendarOptions: MbscEventcalendarOptions = {
selectMultipleEvents: true,
view: {
agenda: { type: 'month' },
},
onEventUpdate: (args) => {
if (args.isDelete) {
if (!this.confirmOpen) {
this.deleteSelectedEvents();
}
return false;
}
return true;
},
onEventDelete: () => {
if (!this.confirmOpen) {
this.deleteSelectedEvents();
return false;
}
return true;
},
onEventRightClick: (args) => {
args.domEvent.preventDefault();
this.selectedEvent = args.event;
this.menuAnchor = args.domEvent.target;
setTimeout(() => {
this.menu.open();
});
},
};
menuOptions: MbscSelectOptions = {
buttons: [],
data: [
{ value: 'update', text: 'Update' },
{ value: 'delete', text: 'Delete' },
],
display: 'anchored',
touchUi: false,
onChange: (args) => {
if (args.value === 'update') {
this.updateSelectedEvents();
} else if (args.value === 'delete') {
this.deleteSelectedEvents();
}
},
onClose: () => {
setTimeout(() => {
// Clear selection
this.menuAction = null;
});
},
};
updateSelectedEvents(): void {
const updatedEvents = [...this.myEvents];
const events = this.selectedEvents.length === 0 && this.selectedEvent ? [this.selectedEvent] : this.selectedEvents;
for (const event of events) {
const index = updatedEvents.findIndex((x) => x.id === event.id);
// Handle recurring event occurrence
if (event.recurring) {
// Create a new event, with updated color and id
const newEvent: MbscCalendarEvent = {
...event,
color: 'orange',
id: event.id + '_' + formatDate('YYYY-MM-DD', event.start as Date),
recurring: undefined,
};
// Update the original event with a recurring exception
const updatedEvent = event.original!;
const updatedExceptionDates = (updatedEvent.recurringException as Date[]) || [];
updatedExceptionDates.push(event.start as Date);
updatedEvent.recurringException = updatedExceptionDates;
updatedEvents.splice(index, 1, updatedEvent);
updatedEvents.push(newEvent);
} else {
// Update the event color
const updatedEvent = { ...event, color: 'orange' };
updatedEvents.splice(index, 1, updatedEvent);
}
}
this.myEvents = updatedEvents;
this.selectedEvents = [];
this.notify.toast({
message: "All selected event's color changed to orange",
});
}
deleteSelectedEvents(): void {
const events = this.selectedEvents.length === 0 && this.selectedEvent ? [this.selectedEvent] : this.selectedEvents;
this.confirmOpen = true;
this.notify.confirm({
title: 'Are you sure you want to delete the following events?',
message: events.map((e) => e.title).join(', '),
okText: 'Delete',
callback: (result) => {
if (result) {
const updatedEvents = [...this.myEvents];
for (const event of events) {
const index = updatedEvents.findIndex((x) => x.id === event.id);
// Handle recurring event occurrence
if (event.recurring) {
// Update the original event with a recurring exception
const updatedEvent = event.original!;
const updatedExceptionDates = (updatedEvent.recurringException as Date[]) || [];
updatedExceptionDates.push(event.start as Date);
updatedEvent.recurringException = updatedExceptionDates;
updatedEvents.splice(index, 1, updatedEvent);
} else {
// Remove the event
updatedEvents.splice(index, 1);
}
}
this.myEvents = updatedEvents;
this.selectedEvents = [];
this.notify.toast({
message: 'Deleted',
});
}
this.confirmOpen = false;
},
});
}
selectAllEvents(): void {
this.selectedEvents = this.calendar.getEvents();
this.notify.toast({
message: 'All events selected from view',
});
}
resetSelection(): void {
this.selectedEvents = [];
this.notify.toast({
message: 'Selection cleared',
});
}
onKeyDown(ev: KeyboardEvent): void {
if (!this.confirmOpen && (ev.code === 'Delete' || ev.code === 'Backspace' || ev.keyCode === 8 || ev.keyCode === 46)) {
this.deleteSelectedEvents();
}
}
ngOnInit(): void {
this.http.jsonp<MbscCalendarEvent[]>('https://trial.mobiscroll.com/events/?vers=5', 'callback').subscribe((resp) => {
this.myEvents = resp;
});
}
}
<mbsc-page class="mds-bulk-actions" (keydown)="onKeyDown($event)">
<div class="mbsc-grid mbsc-no-padding">
<div class="mbsc-row">
<div class="mds-bulk-actions-calendar mbsc-col-sm-9 mbsc-push-sm-3">
<mbsc-eventcalendar
#calendar
[data]="myEvents"
[options]="calendarOptions"
[(selectedEvents)]="selectedEvents"
[selectMultipleEvents]="true"
></mbsc-eventcalendar>
<mbsc-select style="display: none" #menu [(ngModel)]="menuAction" [anchor]="menuAnchor" [options]="menuOptions"> </mbsc-select>
</div>
<div class="mbsc-col-sm-3 mbsc-pull-sm-9 mbsc-flex-col">
<div class="mbsc-button-group-block">
<mbsc-button (click)="selectAllEvents()">Select all from view</mbsc-button>
<mbsc-button (click)="resetSelection()">Reset selection</mbsc-button>
<mbsc-button (click)="updateSelectedEvents()">Update selected</mbsc-button>
</div>
<div class="mbsc-form-group-title">Currently selected</div>
<div class="mds-bulk-actions-event-list mbsc-padding mbsc-flex-1-1">
<ul>
<li *ngFor="let event of selectedEvents;">{{event.title}}</li>
</ul>
</div>
</div>
</div>
</div>
</mbsc-page>
.mds-bulk-actions,
.mds-bulk-actions .mbsc-grid,
.mds-bulk-actions .mbsc-row,
.mds-bulk-actions .mbsc-col-sm-9,
.mds-bulk-actions .mbsc-col-sm-3 {
height: 100%;
}
.mds-bulk-actions-calendar {
border-left: 1px solid #ccc;
}
.mds-bulk-actions-event-list {
overflow: auto;
padding-top: 0;
padding-bottom: 0;
}