Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion components/scheduler/editing/edit-appointments.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Main events you need to implement so you can store the appointment information c

* `OnCreate` - fires when the user saves a new appointment, including an exception for a recurring appointment.
* `OnUpdate` - fires when the user changes an existing appointment. Fires for the recurring appointment when an exception has been created for it.
* `OnDelete` - fires when the user deletes and appointment (including a recurring appointment). You can also enable a [delete confirmation dialog](#delete-confirmation-dialog).
* `OnDelete` - fires when the user deletes an appointment (including a recurring appointment). You can also enable a [delete confirmation dialog](#delete-confirmation-dialog).

There are two other events that you are not required to handle - you can use them to implement application logic:

Expand All @@ -45,6 +45,8 @@ There are two other events that you are not required to handle - you can use the
* `OnEdit` does not fire when the user drags to resize or move appointments, it fires only for the advanced edit form (double clicks on the appointment).
* `OnCancel` - fires when the user clicks the `Cancel` button in the edit form or the `[x]` close button at the window titlebar to discard the changes they just made to an appointment.

The event arguments that are received by the `OnEdit`, `OnUpdate`, and `OnDelete` events include a `EditMode` property that indicates whether the user chose to delete the entire series (`SchedulerRecurrenceEditMode.Series`) or only a single occurrence (`SchedulerRecurrenceEditMode.Occurrence`). For detailed information and examples, see the [Handling Recurring Appointments in CRUD Events](slug:scheduler-recurrence#handling-recurring-appointments-in-crud-events) section.


## User Experience

Expand Down
172 changes: 172 additions & 0 deletions components/scheduler/recurrence.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The Telerik Scheduler for Blazor supports displaying and editing of recurring ap
* Configure the Scheduler for using recurring appointments.
* Define recurrence rules and recurrence exceptions in the Scheduler data.
* Edit recurring appointments and exceptions.
* Handle editing and deleting recurring appointments with the recurrence context.

## Basics

Expand Down Expand Up @@ -219,6 +220,177 @@ A single Scheduler data item defines one series of recurring appointments. Set t
}
````

## Handling Recurring Appointments in CRUD Events

When users edit, update, or delete a recurring appointment, the Scheduler prompts them to choose whether to modify only the current occurrence or the entire series. This choice is reflected in the `EditMode` property of the event arguments.

### RecurrenceEditMode Property

The `OnEdit`, `OnUpdate`, and `OnDelete` event handlers receive event arguments that include a `EditMode` property. This property indicates the user's choice when interacting with recurring appointments:

* `SchedulerRecurrenceEditMode.Series` - The user chose to edit or delete the entire series of recurring appointments.
* `SchedulerRecurrenceEditMode.Occurrence` - The user chose to edit or delete only a single occurrence of the recurring appointment.

### Example

You can use the `EditMode` property to implement different logic based on whether the user is modifying a single occurrence or the entire series.

>caption Handle RecurrenceEditMode in OnUpdate and OnDelete events

````RAZOR
<TelerikScheduler Data="@SchedulerData"
@bind-Date="@SchedulerDate"
@bind-View="@SchedulerView"
AllowCreate="true"
AllowDelete="true"
AllowUpdate="true"
OnCreate="@OnSchedulerCreate"
OnEdit="@OnSchedulerEdit"
OnDelete="@OnSchedulerDelete"
OnUpdate="@OnSchedulerUpdate"
Height="600px">
<SchedulerViews>
<SchedulerDayView StartTime="@SchedulerViewStartTime" />
<SchedulerWeekView StartTime="@SchedulerViewStartTime" />
<SchedulerMonthView />
</SchedulerViews>
</TelerikScheduler>

@code {
private List<Appointment> SchedulerData { get; set; } = new();
private DateTime SchedulerDate { get; set; } = DateTime.Today;
private SchedulerView SchedulerView { get; set; } = SchedulerView.Week;
private DateTime SchedulerViewStartTime { get; set; } = DateTime.Today.AddHours(8);

private void OnSchedulerCreate(SchedulerCreateEventArgs args)
{
Appointment item = (Appointment)args.Item;
SchedulerData.Add(item);
}

private void OnSchedulerEdit(SchedulerEditEventArgs args)
{
Appointment item = (Appointment)args.Item;

// OnEdit fires when the user is about to edit or create an appointment
// SchedulerRecurrenceEditMode indicates whether they chose to edit the series or occurrence
if (args.EditMode == SchedulerRecurrenceEditMode.Series)
{
Console.WriteLine("User chose to edit the entire series");
// The item represents the recurring appointment with RecurrenceRule
}
else if (args.EditMode == SchedulerRecurrenceEditMode.Occurrence)
{
Console.WriteLine("User chose to edit only this occurrence");
// The item will have RecurrenceId set to the parent appointment's Id
Console.WriteLine($"Editing exception for recurring appointment: {item.RecurrenceId}");
}

// You can cancel the event to prevent editing
// args.IsCancelled = true;
}

private void OnSchedulerUpdate(SchedulerUpdateEventArgs args)
{
Appointment item = (Appointment)args.Item;

if (args.EditMode == SchedulerRecurrenceEditMode.Series)
{
// User chose to update the entire series
Console.WriteLine("Updating entire series of recurring appointments");

// Update the recurring appointment
int originalItemIndex = SchedulerData.FindIndex(a => a.Id == item.Id);
if (originalItemIndex >= 0)
{
SchedulerData[originalItemIndex] = item;
}
}
else if (args.EditMode == SchedulerRecurrenceEditMode.Occurrence)
{
// User chose to update only this occurrence
Console.WriteLine("Creating exception for single occurrence");

// This creates a new exception appointment
// The item will have RecurrenceId pointing to the parent
int originalItemIndex = SchedulerData.FindIndex(a => a.Id == item.Id);
if (originalItemIndex >= 0)
{
SchedulerData[originalItemIndex] = item;
}
}
}

private void OnSchedulerDelete(SchedulerDeleteEventArgs args)
{
Appointment item = (Appointment)args.Item;

if (args.EditMode == SchedulerRecurrenceEditMode.Series)
{
// User chose to delete the entire series
Console.WriteLine("Deleting entire series");

// Remove the recurring appointment
SchedulerData.Remove(item);

// Optionally, remove all exceptions for this series
if (!string.IsNullOrEmpty(item.RecurrenceRule))
{
SchedulerData.RemoveAll(a => a.RecurrenceId?.Equals(item.Id) == true);
}
}
else if (args.EditMode == SchedulerRecurrenceEditMode.Occurrence)
{
// User chose to delete only this occurrence
Console.WriteLine("Deleting single occurrence");

if (item.RecurrenceId != null)
{
// This is already an exception, just remove it
SchedulerData.Remove(item);

// Update the parent appointment's RecurrenceExceptions list
var parentAppointment = SchedulerData.FirstOrDefault(a => a.Id.Equals(item.RecurrenceId));
if (parentAppointment != null)
{
// Remove the exception date from the parent's list
parentAppointment.RecurrenceExceptions?.Remove(item.Start);
}
}
else
{
// This is a recurring appointment, create an exception
// The Scheduler automatically adds the occurrence date to RecurrenceExceptions
SchedulerData.Remove(item);
}
}
}

public class Appointment
{
public Guid Id { get; set; }
public string Title { get; set; } = string.Empty;
public DateTime Start { get; set; }
public DateTime End { get; set; }
public bool IsAllDay { get; set; }
public string RecurrenceRule { get; set; } = string.Empty;
public List<DateTime>? RecurrenceExceptions { get; set; }
public Guid? RecurrenceId { get; set; }

public Appointment()
{
Id = Guid.NewGuid();
}
}
}
````

### Important Considerations

* When the user edits or deletes a single occurrence of a recurring appointment, the Scheduler automatically manages the `RecurrenceExceptions` list and creates exception appointments with the appropriate `RecurrenceId`.
* The `RecurrenceEditMode` property is only relevant when working with recurring appointments. For regular (non-recurring) appointments, this property is not used.
* When creating a new appointment in a time slot that matches a recurring appointment, the user can choose to create an exception or a new independent appointment.

## Recurrence Editor Components

Telerik UI for Blazor provides standalone components that you can use to edit recurring appointments outside the Scheduler or in a [custom Scheduler popup edit form](slug:scheduler-kb-custom-edit-form).
Expand Down