Recurring Event Add & Edit
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
clickToCreate: true,
// click to create is on dragToCreate: true,
// drag to create is on dragToMove: true,
// reordering is on dragToResize: true,
// resizing is on eventDelete: true
// deleting is on Fine-tune drag & drop with these options, which are false by default.
Usage
locale: localeEn Selecting the locale loads the localized settings and the translated UI text.
Recurring Event Add & Edit
As seen in the previous example, an add/edit form can be created with custom and base event fields. While the CRUD example features delete with undo, this example shows off how to build a fully customizable recurrence editor right in the add/edit screen.
Above some common presets, like Daily, Weekly on X day, Monthly on Xth, Annually on the same day, Every Weekday a fully custom recurrence editor is implemented.
Copy & paste or delve into the code and understand how to generate recurrence objects or RRULES as seen in this live rule builder.
Demo
The live demo didn't load.
Try it on demo.mobiscroll.comon day of
The event will be repeated every day or every x days, depending on the value
The event will be repeated every x weeks on specific weekdays
The event will be repeated every x months on specific day of the month
The event will be repeated every x years on specific day of a specific month

Code
import { CommonModule } from '@angular/common';
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import {
formatDate,
MbscCalendarEvent,
MbscDatepickerOptions,
MbscEventcalendarOptions,
MbscModule,
MbscPopup,
MbscPopupOptions,
setOptions,
updateRecurringEvent ,
} from '@mobiscroll/angular';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
const days = [
{
name: 'Sunday',
short: 'SU',
checked: true,
},
{
name: 'Monday',
short: 'MO',
checked: false,
},
{
name: 'Tuesday',
short: 'TU',
checked: false,
},
{
name: 'Wednesday',
short: 'WE',
checked: false,
},
{
name: 'Thursday',
short: 'TH',
checked: false,
},
{
name: 'Friday',
short: 'FR',
checked: false,
},
{
name: 'Saturday',
short: 'SA',
checked: false,
},
];
const ordinalList: any = { 1: 'first', 2: 'second', 3: 'third', 4: 'fourth' };
function getWeekDayNum(date: Date): number {
const year = date.getFullYear();
const month = date.getMonth();
const firstDayOfMonth = new Date(year, month, 1);
const lastDayOfMonth = new Date(year, month + 1, 0);
let count = 0;
for (let d = firstDayOfMonth; d < lastDayOfMonth; d.setDate(d.getDate() + 7)) {
if (date >= d) {
count++;
} else {
break;
}
}
return Math.max(1, count);
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
standalone: true,
imports: [CommonModule, FormsModule, MbscModule],
})
export class AppComponent implements OnInit {
@ViewChild('popup', { static: false })
popup!: MbscPopup;
popupEventTitle: string | undefined;
popupEventDescription = '';
popupEventAllDay = true;
popupEventDates: any;
calendarSelectedDate: any = new Date();
switchLabel: any = 'All-day';
myEvents: MbscCalendarEvent[] = [
{
id: 1,
start: '10:00',
end: '12:00',
title: 'Take vitamins',
allDay: false,
color: '#67ab0d',
recurring: {
repeat: 'daily',
weekDays: 'MO,TU,WE,TH,FR,SA,SU',
},
},
{
id: 2,
start: '18:00',
end: '20:00',
recurring: {
repeat: 'weekly',
weekDays: 'MO',
},
title: 'Football training',
allDay: false,
color: '#fd966a',
},
{
id: 3,
start: '17:00',
end: '18:00',
recurring: {
repeat: 'monthly',
day: 10,
},
title: 'Rent payment',
allDay: false,
color: '#3ea39e',
},
{
id: 4,
recurring: {
repeat: 'yearly',
day: 6,
month: 6,
},
title: 'Dexter BD',
allDay: true,
color: '#d00f0f',
},
];
repeatData = [
{
value: 'norepeat',
text: 'Does not repeat',
},
{
value: 'daily',
text: 'Daily',
},
{
value: 'weekly',
text: 'Weekly',
},
{
value: 'monthly',
text: 'Monthly',
},
{
value: 'monthly-pos',
text: 'Monthly',
},
{
value: 'yearly',
text: 'Yearly',
},
{
value: 'yearly-pos',
text: 'Yearly',
},
{
value: 'weekday',
text: 'Every weekday (Monday to Friday)',
},
{
value: 'custom',
text: 'Custom',
},
];
selectedRepeat = 'norepeat';
selectResponsive = {
xsmall: {
touchUi: true,
},
small: {
touchUi: false,
},
};
weekDays = ['SU'];
showCustomRepeat = false;
repeatType = 'daily';
repeatNr = 1;
monthlyDays = [1];
monthlyDay = 1;
yearlyDays = [1];
yearlyDay = 1;
months = [
{
value: 1,
text: 'January',
},
{
value: 2,
text: 'February',
},
{
value: 3,
text: 'March',
},
{
value: 4,
text: 'April',
},
{
value: 5,
text: 'May',
},
{
value: 6,
text: 'June',
},
{
value: 7,
text: 'July',
},
{
value: 8,
text: 'August',
},
{
value: 9,
text: 'September',
},
{
value: 10,
text: 'October',
},
{
value: 11,
text: 'November',
},
{
value: 12,
text: 'December',
},
];
selectedMonth = 1;
untilDate: any;
occurrences = 10;
condition = 'never';
tempEvent: any;
@ViewChild('recurringEditModePopup', { static: false })
recurringEditModePopup!: MbscPopup;
recurringEditMode: any = 'current';
newEvent: MbscCalendarEvent = {};
originalRecurringEvent: any;
eventOccurrence: MbscCalendarEvent = {};
editFromPopup = false;
recurringDelete = false;
recurringActionText = 'Edit';
calendarOptions: MbscEventcalendarOptions = {
clickToCreate: 'double',
dragToCreate: true,
dragToMove: true,
dragToResize: true,
view: {
scheduler: { type: 'week' },
},
onEventClick: (args: any) => {
const event = args.event;
this.isEdit = true;
this.tempEvent = args.event;
// Recurring event
if (event.recurring) {
this.originalRecurringEvent = event['original'];
this.eventOccurrence = { ...event };
// Fill popup form with event data
this.loadPopupForm(event);
} else {
this.originalRecurringEvent = {};
// Fill popup form with event data
this.loadPopupForm(event);
}
// Set popup options
this.popupHeaderText = 'Edit event';
this.popupButtons = this.popupEditButtons;
this.popupAnchor = args.domEvent.currentTarget;
// Open the popup
this.popup.open();
},
onEventUpdate: (args: any) => {
const event = args.event;
if (event.recurring) {
this.originalRecurringEvent = args.oldEvent;
// We need this on delete
this.tempEvent = event;
this.eventOccurrence = args.oldEventOccurrence;
if (args.domEvent.keyCode === 46) {
this.recurringActionText = 'Delete';
this.recurringDelete = true;
this.recurringEditModePopup.open();
} else {
this.recurringActionText = 'Edit';
this.recurringDelete = false;
this.recurringEditModePopup.open();
}
return false;
} else {
return true;
}
},
onEventCreate: (args: any) => {
const originEvent = args.originEvent;
if (originEvent && originEvent.recurring) {
this.newEvent = args.event;
return false;
} else {
return true;
}
},
onEventCreated: (args: any) => {
setTimeout(() => {
this.isEdit = false;
this.tempEvent = args.event;
// Fill popup form with event data
this.loadPopupForm(args.event);
// Set popup options
this.popupHeaderText = 'New Event';
this.popupButtons = this.popupAddButtons;
this.popupAnchor = args.target;
this.resetCustomValues();
// Open the popup
this.popup.open();
});
},
onEventDeleted: (args: any) => {
setTimeout(() => {
this.deleteEvent(args.event);
});
},
onEventUpdated: () => {
// Here you can update the event in your storage as well, after drag & drop or resize
// ...
},
};
popupHeaderText!: string;
popupAnchor: HTMLElement | undefined;
popupAddButtons = [
'cancel',
{
handler: () => {
this.saveEvent();
},
keyCode: 'enter',
text: 'Add',
cssClass: 'mbsc-popup-button-primary',
},
];
popupEditButtons = [
'cancel',
{
handler: () => {
if (Object.keys(this.originalRecurringEvent).length !== 0) {
this.editFromPopup = true;
this.recurringActionText = 'Edit';
this.recurringDelete = false;
this.recurringEditModePopup.open();
} else {
this.saveEvent();
}
},
keyCode: 'enter',
text: 'Save',
cssClass: 'mbsc-popup-button-primary',
},
];
popupButtons: any = [];
popupOptions: MbscPopupOptions = {
display: 'bottom',
contentPadding: false,
fullScreen: true,
scrollLock: false,
height: 500,
onClose: () => {
this.repeatData = this.repeatData.filter((item) => item.value !== 'custom-value');
if (!this.isEdit) {
// Refresh the list, if add popup was canceled, to remove the temporary event
this.myEvents = [...this.myEvents];
}
this.editFromPopup = false;
},
responsive: {
medium: {
display: 'anchored',
width: 510,
fullScreen: false,
touchUi: false,
},
},
cssClass: 'md-recurring-event-editor-popup',
};
editModePopupOptions: MbscPopupOptions = {
display: 'bottom',
contentPadding: false,
buttons: [
'cancel',
{
text: 'Ok',
keyCode: 'enter',
handler: () => {
if (this.recurringDelete) {
this.deleteRecurringEvent();
} else {
if (this.editFromPopup) {
this.setTempEvent();
}
if (this.recurringEditMode === 'current') {
delete this.tempEvent.id;
delete this.tempEvent.recurring;
delete this.tempEvent.recurringException;
}
const events = updateRecurringEvent(
this.originalRecurringEvent,
this.eventOccurrence,
this.editFromPopup ? null : this.newEvent,
this.editFromPopup ? this.tempEvent : null,
this.recurringEditMode,
);
// Update event
let newEventList = [...this.myEvents];
const index = newEventList.findIndex((x) => x.id === events.updatedEvent.id);
newEventList[index] = events.updatedEvent;
// Add new event
if (events.newEvent) {
newEventList = [...newEventList, events.newEvent];
}
this.myEvents = newEventList;
this.popup.close();
this.recurringEditModePopup.close();
}
},
cssClass: 'mbsc-popup-button-primary',
},
],
onClose: () => {
this.recurringEditMode = 'current';
},
};
datePickerControls = ['date'];
datePickerResponsive: any = {
medium: {
controls: ['calendar'],
touchUi: false,
},
};
datetimePickerControls = ['datetime'];
datetimePickerResponsive = {
medium: {
controls: ['calendar', 'time'],
touchUi: false,
},
};
datePickerOptions: MbscDatepickerOptions = {
select: 'range',
showRangeLabels: false,
touchUi: true,
};
isEdit = false;
deleteRecurringEvent(): void {
switch (this.recurringEditMode) {
case 'following': {
let followingExceptions = this.tempEvent.recurringException || [];
followingExceptions = [...followingExceptions, this.tempEvent.start];
this.originalRecurringEvent.recurringException = followingExceptions;
this.originalRecurringEvent.recurring.until = this.tempEvent.start;
this.myEvents = [...this.myEvents];
break;
}
case 'all':
this.myEvents = this.myEvents.filter((item) => item.id !== this.tempEvent.id);
break;
case 'current':
default: {
let currentExceptions = this.tempEvent.recurringException || [];
currentExceptions = [...currentExceptions, this.tempEvent.start];
this.originalRecurringEvent.recurringException = currentExceptions;
this.myEvents = [...this.myEvents];
break;
}
}
this.popup.close();
this.recurringEditModePopup.close();
}
loadPopupForm(event: MbscCalendarEvent): void {
const startDate = new Date(event.start as any);
this.popupEventTitle = event.title;
this.popupEventDescription = event['description'];
this.popupEventDates = [startDate, event.end];
this.untilDate = formatDate('YYYY-MM-DD', new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate() + 1));
this.popupEventAllDay = event.allDay || false;
this.updateCustomForm();
}
getCustomRule(): any {
let recurringRule: any;
const d = this.editFromPopup ? this.popupEventDates[0] : new Date(this.tempEvent.start);
const weekday = d.getDay();
const monthday = d.getDate();
const weekNr = getWeekDayNum(d);
if (this.editFromPopup && this.tempEvent.start && this.tempEvent.recurring) {
switch (this.selectedRepeat) {
default:
case 'daily':
recurringRule = {
repeat: 'daily',
};
break;
case 'weekly':
recurringRule = {
repeat: 'weekly',
weekDays: days[weekday].short,
};
break;
case 'monthly':
recurringRule = {
repeat: 'monthly',
day: monthday,
};
break;
case 'monthly-pos':
recurringRule = {
repeat: 'monthly',
weekDays: days[weekday].short,
pos: weekNr,
};
break;
case 'yearly':
recurringRule = {
repeat: 'yearly',
day: monthday,
month: d.getMonth() + 1,
};
break;
case 'yearly-pos':
recurringRule = {
repeat: 'yearly',
month: d.getMonth() + 1,
weekDays: days[weekday].short,
pos: weekNr,
};
break;
}
} else {
switch (this.selectedRepeat) {
case 'daily':
recurringRule = { repeat: 'daily' };
break;
case 'weekly':
recurringRule = { repeat: 'weekly', weekDays: days[d.getDay()].short };
break;
case 'monthly':
recurringRule = { repeat: 'monthly', day: d.getDate() };
break;
case 'monthly-pos':
recurringRule = { repeat: 'monthly', weekDays: days[weekday].short, pos: weekNr };
break;
case 'yearly':
recurringRule = { repeat: 'yearly', month: d.getMonth() + 1 };
break;
case 'yearly-pos':
recurringRule = { repeat: 'yearly', month: d.getMonth() + 1, weekDays: days[weekday].short, pos: weekNr };
break;
case 'weekday':
recurringRule = { repeat: 'weekly', weekDays: 'MO,TU,WE,TH,FR' };
break;
case 'custom':
case 'custom-value':
recurringRule = {
repeat: this.repeatType,
interval: this.repeatNr,
};
switch (this.repeatType) {
case 'weekly':
recurringRule.weekDays = this.weekDays.join(',');
break;
case 'monthly':
recurringRule.day = this.monthlyDay;
break;
case 'yearly':
recurringRule.day = this.yearlyDay;
recurringRule.month = this.selectedMonth;
break;
}
switch (this.condition) {
case 'until':
recurringRule.until = this.untilDate;
break;
case 'count':
recurringRule.count = this.occurrences;
break;
}
break;
}
}
return recurringRule;
}
setTempEvent(): void {
this.tempEvent.title = this.popupEventTitle;
this.tempEvent.description = this.popupEventDescription;
this.tempEvent.start = this.popupEventDates[0];
this.tempEvent.end = this.popupEventDates[1];
this.tempEvent.allDay = this.popupEventAllDay;
this.tempEvent.recurring = this.getCustomRule();
}
saveEvent(): void {
this.setTempEvent();
if (this.isEdit) {
// Update the event in the list
this.myEvents = [...this.myEvents];
// Here you can update the event in your storage as well
// ...
} else {
// Add the new event to the list
this.myEvents = [...this.myEvents, this.tempEvent];
// Here you can add the event to your storage as well
// ...
}
// Navigate the calendar
this.navigateTo();
// Close the popup
this.popup.close();
}
deleteEvent(event: MbscCalendarEvent): void {
this.myEvents = this.myEvents.filter((item) => item.id !== event.id);
}
onDeleteClick(): void {
if (this.tempEvent.recurring) {
this.recurringActionText = 'Delete';
this.recurringDelete = true;
this.recurringEditModePopup.open();
} else {
this.deleteEvent(this.tempEvent);
this.popup.close();
}
}
// Set custom values to default
resetCustomValues(): void {
this.repeatType = 'daily';
this.repeatNr = 1;
this.condition = 'never';
this.occurrences = 10;
this.selectedMonth = 1;
this.monthlyDay = 1;
this.yearlyDay = 1;
this.weekDays = ['SU'];
this.selectedRepeat = 'norepeat';
this.showCustomRepeat = false;
this.repeatData = this.repeatData.filter((item) => item.value !== 'custom-value');
}
updateCustomForm(): void {
const d = new Date(this.tempEvent.start);
const weekday = d.getDay();
const monthday = d.getDate();
const newData = [...this.repeatData];
const weekNr = getWeekDayNum(d);
// Update select texts by selected date
for (const item of newData) {
switch (item.value) {
case 'weekly':
item.text = 'Weekly on ' + days[weekday].name;
break;
case 'monthly':
item.text = 'Monthly on day ' + monthday;
break;
case 'yearly':
item.text = 'Annually on ' + this.months[d.getMonth()].text + ' ' + monthday;
break;
case 'monthly-pos':
item.text = 'Monthly on the ' + ordinalList[weekNr] + ' ' + days[weekday].name;
break;
case 'yearly-pos':
item.text = 'Annually on the ' + ordinalList[weekNr] + ' ' + days[weekday].name + ' of ' + this.months[d.getMonth()];
break;
default:
}
}
this.repeatData = newData;
const rec = this.tempEvent.recurring;
if (rec) {
this.repeatType = rec.repeat;
this.weekDays = rec.repeat === 'weekly' ? rec.weekDays.split(',') : ['SU'];
if (rec.interval) {
// Set custom text
let customText = '';
this.repeatNr = rec.interval;
switch (rec.repeat) {
case 'daily':
customText = this.repeatNr > 1 ? 'Every ' + this.repeatNr + ' days' : 'Daily';
break;
case 'weekly':
customText = this.repeatNr > 1 ? 'Every ' + this.repeatNr + ' weeks' : 'Weekly';
customText += ' on ' + rec.weekDays;
break;
case 'monthly':
this.monthlyDay = rec.day;
customText = this.repeatNr > 1 ? 'Every ' + this.repeatNr + ' months' : 'Monthly';
customText += ' on day ' + this.monthlyDay;
break;
case 'yearly':
this.yearlyDay = rec.day;
this.selectedMonth = rec.month;
customText = this.repeatNr > 1 ? 'Every ' + this.repeatNr + ' years' : 'Annualy';
customText += ' on ' + this.months[this.selectedMonth - 1].text + ' ' + this.yearlyDay;
break;
}
if (rec.until) {
this.condition = 'until';
this.untilDate = rec.until;
customText += ' until ' + formatDate('MMMM D, YYYY', new Date(this.untilDate));
} else if (rec.count) {
this.condition = 'count';
this.occurrences = rec.count;
customText += ', ' + this.occurrences + ' times';
} else {
this.condition = 'never';
}
// Add custom value
this.repeatData = [...this.repeatData, { value: 'custom-value', text: customText }];
// Set custom value
this.selectedRepeat = 'custom-value';
} else if (rec.weekDays === 'MO,TU,WE,TH,FR') {
this.selectedRepeat = 'weekday';
} else {
this.selectedRepeat = rec.repeat;
}
} else {
this.resetCustomValues();
}
this.showCustomRepeat = this.selectedRepeat === 'custom' || this.selectedRepeat === 'custom-value';
}
// Popuplate data for months
populateMonthDays(month: number, type: string): void {
const day30 = [2, 4, 6, 9, 11];
const newValues = [];
for (let i = 1; i <= 31; i++) {
if (!(i === 31 && day30.includes(month)) && !(i === 30 && month === 2)) {
newValues.push(i);
}
}
if (type === 'monthly') {
this.monthlyDays = newValues;
this.monthlyDay = 1;
} else {
this.yearlyDays = newValues;
this.yearlyDay = 1;
}
}
monthChange(ev: any): void {
this.selectedMonth = ev.value;
this.yearlyDay = 1;
this.populateMonthDays(ev.value, 'yearly');
}
navigateTo(): void {
const rec = this.tempEvent.recurring;
const d = new Date(this.tempEvent.start);
let nextYear = 0;
// Navigate the calendar to the correct view
if (rec && rec.repeat === 'yearly') {
if (d.getMonth() + 1 > +rec.month && d.getDay() > +rec.day) {
nextYear = 1;
}
this.calendarSelectedDate = new Date(d.getFullYear() + nextYear, rec.month - 1, rec.day);
} else {
this.calendarSelectedDate = d;
}
}
ngOnInit(): void {
this.populateMonthDays(1, 'monthly');
this.populateMonthDays(1, 'yearly');
}
}
<mbsc-eventcalendar [data]="myEvents" [options]="calendarOptions" [(selectedDate)]="calendarSelectedDate"></mbsc-eventcalendar>
<mbsc-popup [options]="popupOptions" [anchor]="popupAnchor" [buttons]="popupButtons" [headerText]="popupHeaderText" #popup>
<div class="mbsc-form-group">
<mbsc-input label="Title" [(ngModel)]="popupEventTitle"></mbsc-input>
<mbsc-textarea label="Description" [(ngModel)]="popupEventDescription"></mbsc-textarea>
</div>
<div class="mbsc-form-group">
<mbsc-switch label="All-day" [(ngModel)]="popupEventAllDay"></mbsc-switch>
<mbsc-datepicker
[(ngModel)]="popupEventDates"
[options]="datePickerOptions"
[controls]="popupEventAllDay ? datePickerControls : datetimePickerControls"
[responsive]="popupEventAllDay ? datePickerResponsive : datetimePickerResponsive"
[startInput]="startInput"
[endInput]="endInput"
></mbsc-datepicker>
<mbsc-input #startInput label="Starts"></mbsc-input>
<mbsc-input #endInput label="Ends"></mbsc-input>
<mbsc-select [(ngModel)]="selectedRepeat" [data]="repeatData" label="Repeats" [responsive]="selectResponsive"></mbsc-select>
</div>
<div *ngIf="selectedRepeat === 'custom' || selectedRepeat === 'custom-value'">
<mbsc-segmented-group [(ngModel)]="repeatType">
<mbsc-segmented value="daily">Daily</mbsc-segmented>
<mbsc-segmented value="weekly">Weekly</mbsc-segmented>
<mbsc-segmented value="monthly">Monthly</mbsc-segmented>
<mbsc-segmented value="yearly">Yearly</mbsc-segmented>
</mbsc-segmented-group>
<div class="md-recurrence-options">
<span>Repeat every</span>
<span class="md-recurrence-input md-recurrence-input-nr">
<mbsc-input [(ngModel)]="repeatNr" inputStyle="outline"></mbsc-input>
</span>
<span *ngIf="repeatType === 'daily'">day(s)</span>
<span *ngIf="repeatType === 'monthly'">
month(s) on day
<span class="md-recurrence-input md-recurrence-input-nr">
<mbsc-select [(ngModel)]="monthlyDay" [data]="monthlyDays" inputStyle="outline"></mbsc-select>
</span>
</span>
<span *ngIf="repeatType === 'yearly'">
year(s) <br />on day
<span class="md-recurrence-input md-recurrence-input-nr">
<mbsc-select [(ngModel)]="yearlyDay" [data]="yearlyDays" inputStyle="outline"></mbsc-select>
</span>
<span>of</span>
<span class="md-recurrence-input">
<mbsc-select [(ngModel)]="selectedMonth" [data]="months" inputStyle="outline" (onChange)="monthChange($event)"></mbsc-select>
</span>
</span>
<p *ngIf="repeatType === 'daily'" class="md-recurrence-desc">
The event will be repeated every day or every x days, depending on the value
</p>
<p *ngIf="repeatType === 'weekly'" class="md-recurrence-desc">The event will be repeated every x weeks on specific weekdays</p>
<p *ngIf="repeatType === 'monthly'" class="md-recurrence-desc">
The event will be repeated every x month on specific day of the month
</p>
<p *ngIf="repeatType === 'yearly'" class="md-recurrence-desc">
The event will be repeated every x years on specific day of a specific month
</p>
</div>
<mbsc-segmented-group *ngIf="repeatType === 'weekly'" [(ngModel)]="weekDays" select="multiple">
<mbsc-segmented value="SU">Sun</mbsc-segmented>
<mbsc-segmented value="MO">Mon</mbsc-segmented>
<mbsc-segmented value="TU">Tue</mbsc-segmented>
<mbsc-segmented value="WE">Wen</mbsc-segmented>
<mbsc-segmented value="TH">Thu</mbsc-segmented>
<mbsc-segmented value="FR">Fri</mbsc-segmented>
<mbsc-segmented value="SA">Sat</mbsc-segmented>
</mbsc-segmented-group>
<div class="md-recurrence-ends">Ends</div>
<div class="mbsc-form-group">
<mbsc-radio-group [(ngModel)]="condition">
<mbsc-radio label="Never" position="start" description="The event will repeat indefinitely" value="never"> </mbsc-radio>
<mbsc-radio value="until" position="start">
Until
<span class="md-recurrence-input">
<mbsc-datepicker
[controls]="['calendar']"
display="anchored"
[touchUi]="false"
dateFormat="YYYY-MM-DD"
returnFormat="iso8601"
[(ngModel)]="untilDate"
(click)="condition = 'until'"
class="custom-repeat-input custom-specific-date"
inputStyle="outline"
></mbsc-datepicker>
</span>
<span class="mbsc-description">The event will run until it reaches a specific date</span>
</mbsc-radio>
<mbsc-radio value="count" position="start">
After
<span class="md-recurrence-input md-recurrence-input-nr">
<mbsc-input
class="custom-repeat-input"
inputStyle="outline"
[(ngModel)]="occurrences"
(click)="condition = 'count'"
></mbsc-input>
occurrences
<span class="mbsc-description">The event will repeat until it reaches a certain amount of occurrences</span>
</span>
</mbsc-radio>
</mbsc-radio-group>
</div>
</div>
<div *ngIf="isEdit" class="mbsc-button-group">
<mbsc-button class="mbsc-button-block" color="danger" variant="outline" (click)="onDeleteClick()">Delete event</mbsc-button>
</div>
</mbsc-popup>
<mbsc-popup [options]="editModePopupOptions" #recurringEditModePopup>
<div class="mbsc-form-group">
<div class="mbsc-form-group-title">{{recurringActionText}} recurring event</div>
<mbsc-radio-group [(ngModel)]="recurringEditMode">
<mbsc-radio label="This event only" value="current"></mbsc-radio>
<mbsc-radio label="This and following events" value="following"></mbsc-radio>
<mbsc-radio label="All events" value="all"></mbsc-radio>
</mbsc-radio-group>
</div>
</mbsc-popup>
.md-recurring-event-editor-popup .md-recurrence-input .mbsc-textfield-wrapper {
display: inline-block;
margin: 3px;
z-index: 3;
line-height: normal;
}
.md-recurring-event-editor-popup .md-recurrence-input .mbsc-textfield {
width: 140px;
height: 32px;
}
.md-recurring-event-editor-popup .md-recurrence-input-nr .mbsc-textfield {
width: 90px;
}
.md-recurring-event-editor-popup .md-recurrence-input .mbsc-select-icon {
top: 50%;
height: 1.5em;
margin-top: -0.75em;
}
.md-recurrence-options {
padding: 0 1em;
margin: 1em 0;
}
.md-recurrence-ends {
padding: 0 1em;
margin: 1.25em 0 -1.25em 0;
}
.md-recurrence-desc {
font-size: 12px;
font-weight: normal;
color: #555;
margin: 1em 0;
}
.md-hide-elm {
display: none;
}