# Reactive Forms

The Scheduler provides options for editing its events by using [Reactive Angular Forms](https://angular.dev/guide/forms/reactive-forms).

## Basic Concepts

To modify a Scheduler event or add a new one:

1. Call the [`addEvent`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#addevent) or the [`editEvent`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#editevent) method respectively.
2. Pass the `FormGroup` property as one of its parameters. The [`FormGroup`](https://angular.dev/api/forms/FormGroup) configuration is part of the Angular Forms package.

The following example demonstrates how to add and edit Scheduler events using reactive forms.

[Demo Source](https://demos.telerik.com/kendo-angular-ui/demos/scheduler/editing/reactive-forms/source.txt)

## Setup

To enable the editing mode of the Scheduler in Angular Reactive Forms, attach handlers for the corresponding CRUD data operations.

1. When the user click or double-clicks an empty slot in the Scheduler, the component emits the `slotClick` and `slotDblClick` events. To initiate the `create` action, utilize either of those events.

   ```html
   <kendo-scheduler
       [kendoSchedulerBinding]="events"
       (slotDblClick)="onSlotDblClick($event)"
   >
       
   </kendo-scheduler>
   ```

2. When the user clicks or double-clicks an event in the Scheduler, the component emits the `eventClick` and `eventDblClick` events. To start editing the event in the Scheduler, utilize either of those events and then initiate the `update` action.

   ```html
   <kendo-scheduler
       [kendoSchedulerBinding]="events"
       (slotDblClick)="onSlotDblClick($event)"
       (eventDblClick)="onEventDblClick($event)"
   >
       
   </kendo-scheduler>
   ```

3. Attach handlers for the `save`, `cancel`, and `remove` events.

   ```html
   <kendo-scheduler
       [kendoSchedulerBinding]="events"
       (slotDblClick)="onSlotDblClick($event)"
       (eventDblClick)="onEventDblClick($event)"
       (cancel)="cancelHandler($event)"
       (save)="saveHandler($event)"
       (remove)="removeHandler($event)"
   >
       
   </kendo-scheduler>
   ```

## Edit Operations

The Scheduler provides the following specific edit operations for its displayed events:

* [Editing existing events](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/editing/editing-reactive-forms#editing-existing-events)
* [Adding events](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/editing/editing-reactive-forms#adding-new-events)
* [Saving events](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/editing/editing-reactive-forms#saving-events)
* [Removing events](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/editing/editing-reactive-forms#removing-existing-events)
* [Cancelling the editing of an event](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/editing/editing-reactive-forms#cancelling-event-editing)
* [Dragging events](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/editing/editing-reactive-forms#dragging-events)
* [Resizing events](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/editing/editing-reactive-forms#resizing-events)

### Editing Existing Events

The `FormGroup` configuration describes the view model for that editor.

The `EditMode` contains information about the current editing operation. The supported values are:

* `Series`—Used when the user edits a recurring event instance and the update applies to all events in the series.
* `Occurrence`—Used when the user edits a recurring event instance and the update applies to this instance only.
* `Event`—Used by default when the user edits a non-recurring event.

To enable the edit mode of an event in the Scheduler, use either of the following approaches:

* Inside the corresponding event handler (for example, `eventDblClick`), pass the event to the [`editEvent`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#editevent) method and provide the appropriate editing options as demonstrated in the following example.

  ```ts
  public eventDblClickHandler({ sender, event }): void {
      this.closeEditor(sender);

      // Define all event fields, validators, and default values.
      this.formGroup = this.formBuilder.group({
          'TaskID': event.id,
          'Start': [event.start, Validators.required],
          'End': [event.end, Validators.required],
          'StartTimezone': [event.startTimezone],
          'EndTimezone': [event.endTimezone],
          'IsAllDay': event.isAllDay,
          'Title': event.title,
          'Description': event.description,
          'RecurrenceRule': event.recurrenceRule,
          'RecurrenceID': event.recurrenceId
      });

      sender.editEvent(event, { group: this.formGroup, mode: <Edit Mode> });
  }
  ```

* Enable the edit mode of the Scheduler by utilizing its [`openRecurringConfirmationDialog`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#openrecurringconfirmationdialog) method.

  ```ts
  public eventDblClickHandler({ sender, event }: SlotClickEvent): void {
      this.closeEditor(sender);

      let dataItem = event.dataItem;
      if (this.editService.isRecurring(dataItem)) {
          sender.openRecurringConfirmationDialog(CrudOperation.Edit)
              // The result will be undefined if the dialog was closed.
              .pipe(filter(editMode => editMode !== undefined))
              .subscribe((editMode: EditMode) => {
                  if (editMode === EditMode.Series) {
                      dataItem = this.editService.findRecurrenceMaster(dataItem);
                  }

                  this.formGroup = this.formBuilder.group({
                      // Add the controls required by the event model.
                  });

                  sender.editEvent(dataItem, { group: this.formGroup, mode: editMode });
              });
      } else {
          this.formGroup = this.formBuilder.group({
              // Add the controls required by the event model.
          });

          sender.editEvent(dataItem, { group: this.formGroup });
      }
  }
  ```

### Adding New Events

To show the edit dialog for the new event, call the [`addEvent`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#addevent) method inside the corresponding event handler (for example, `slotDblClick`) and provide the `FormGroup` configuration which describes the view model. You will receive the corresponding information for the clicked slot as an event argument—for example, `start`, `end`, or `isAllDay`.

```ts
public slotDblClickHandler({ sender, start, end, isAllDay }: EventClickEvent): void {
    this.closeEditor(sender);

    this.formGroup = this.formBuilder.group({
        'Start': [start, Validators.required],
        'End': [end, Validators.required],
        'StartTimezone': new FormControl(),
        'EndTimezone': new FormControl(),
        'IsAllDay': isAllDay,
        'Title': new FormControl(''),
        'Description': new FormControl(''),
        'RecurrenceRule': new FormControl(),
        'RecurrenceID': new FormControl()
    });

    sender.addEvent(this.formGroup);
}
```

### Saving Events

When the user clicks the **Save** action of the edit dialog, the Scheduler fires its [`save`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#save) event.

When an event is saved (updated), the Scheduler provides the following possible options:

* Updating the event depending on the currently selected edit mode.
* Switching the current event back to its view mode through its [`closeEvent`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#closeevent) method.

  ```ts
  public saveHandler({ sender, formGroup, isNew, dataItem, mode }: SaveEvent): void {
      if (formGroup.valid) {
          const formValue = formGroup.value;

          if (isNew) {
              this.editService.create(formValue);
          } else {
              this.handleUpdate(dataItem, formValue, mode);
          }

          this.closeEditor(sender);
      }
  }
  ```

The saving of events can result in the following actions:

* An update of a non-recurring item.
* An update of a recurring item along with all items in the series.
* An update of a single instance of recurring items, that is, creating an exception.
* An update of an already existing exception.

```ts
private handleUpdate(item: any, value: any, mode: EditMode): void {
  const service = this.editService;
  if (mode === EditMode.Occurrence) {
    if (service.isException(item)) {
      service.update(item, value);
      } else {
        service.createException(item, value);
      }
      } else {
        // Update non-recurring events or the full recurrence series.
        service.update(item, value);
      }
    }
```

### Removing Existing Events

When the user clicks the **Remove** icon of a displayed event, the Scheduler fires its [`remove`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#remove) event.

Enable the edit mode of the Scheduler during the removal of the event by utilizing its [`openRecurringConfirmationDialog`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#openrecurringconfirmationdialog) or [`openRemoveConfirmationDialog`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#openremoveconfirmationdialog) method inside the event handler.

```ts
public removeHandler({ sender, dataItem }: RemoveEvent): void {
    if (this.editService.isRecurring(dataItem)) {
        sender.openRecurringConfirmationDialog(CrudOperation.Remove)
                // The result will be undefined if the dialog was closed.
                .pipe(filter(editMode => editMode !== undefined))
                .subscribe((editMode) => {
                    this.handleRemove(dataItem, editMode);
                });
    } else {
        sender.openRemoveConfirmationDialog().subscribe((shouldRemove) => {
            if (shouldRemove) {
                this.editService.remove(dataItem);
            }
        });
    }
}
```

The removal of events can result in the following operations:

* A removal of a non-recurring item.
* A removal of a recurring item along with all items in the series.
* A removal of a single instance of recurring items, that is, creating an exception.
* A removal of an already existing exception.

```ts
private handleRemove(item: any, mode: EditMode): void {
    const service = this.editService;
    if (mode === EditMode.Series) {
        service.removeSeries(item);
    } else if (mode === EditMode.Occurrence) {
        if (service.isException(item)) {
            service.remove(item);
        } else {
            service.removeOccurrence(item);
        }
    } else {
        service.remove(item);
    }
}
```

### Cancelling Event Editing

When the user clicks the **Cancel** action of the edit dialog, the Scheduler fires the [`cancel`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#cancel) event. Inside the event handler, switch the event back to view mode by calling the [`closeEvent`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#closeevent) method.

```ts
public cancelHandler({ sender }): void {
    scheduler.closeEvent();

    this.formGroup = undefined;
}
```

### Dragging Events

The Scheduler provides options for editing its events by dragging them to another date or time slot. To update the events after they are dragged by the user, handle the [`dragEnd`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#dragend) event of the Scheduler. The event argument contains the start and end date, the `isAllDay` value, and the resources as updated after dragging.

To disable the dragging of events, use the [`editable`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#editable) and [`drag`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/editablesettings#drag) options.

```ts
    public dragEndHandler({ sender, event, start, end, isAllDay }): void {
        const value = { Start: start, End: end, IsAllDay: isAllDay };
        let dataItem = event.dataItem;

        if (this.editService.isRecurring(dataItem)) {
            sender.openRecurringConfirmationDialog(CrudOperation.Edit)
                .pipe(filter(editMode => editMode !== undefined))
                .subscribe((editMode: EditMode) => {
                    if (editMode === EditMode.Series) {
                        dataItem = this.editService.findRecurrenceMaster(dataItem);

                        // For series edits, keep unchanged date parts from the recurrence-defining event.
                        value.Start = this.seriesDate(dataItem.Start, event.dataItem.Start, start);
                        value.End = this.seriesDate(dataItem.End, event.dataItem.End, end);
                    } else {
                        // For occurrence edits, retain fields and replace the changed values.
                        value = { ...dataItem, ...value };
                    }

                    this.handleUpdate(dataItem, value, editMode);
                });
        } else {
            this.handleUpdate(dataItem, value);
        }
    }

    private seriesDate(head: Date, occurence: Date, current: Date): Date {
        const year = occurence.getFullYear() === current.getFullYear() ? head.getFullYear() : current.getFullYear();
        const month = occurence.getMonth() === current.getMonth() ? head.getMonth() : current.getMonth();
        const date = occurence.getDate() === current.getDate() ? head.getDate() : current.getDate();
        const hours = occurence.getHours() === current.getHours() ? head.getHours() : current.getHours();
        const minutes = occurence.getMinutes() === current.getMinutes() ? head.getMinutes() : current.getMinutes();

        return new Date(year, month, date, hours, minutes);
    }
```

### Resizing Events

The Scheduler provides options for changing the start and end date of an event by dragging its resize handles. To update the events after they are resized by the user, handle the [`resizeEnd`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#resizeend) event of the Scheduler. The event argument contains the start and end date as updated after resizing.

To disable the resizing of events, use the [`editable`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent#editable) and [`resize`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/editablesettings#resize) options.

```ts
    public resizeEndHandler({ sender, event, start, end }): void {
        const value = { Start: start, End: end };
        let dataItem = event.dataItem;

        if (this.editService.isRecurring(dataItem)) {
            sender.openRecurringConfirmationDialog(CrudOperation.Edit)
                .pipe(filter(editMode => editMode !== undefined))
                .subscribe((editMode: EditMode) => {
                    if (editMode === EditMode.Series) {
                        dataItem = this.editService.findRecurrenceMaster(dataItem);

                        // For series edits, keep unchanged date parts from the recurrence-defining event.
                        value.Start = this.seriesDate(dataItem.Start, event.dataItem.Start, start);
                        value.End = this.seriesDate(dataItem.End, event.dataItem.End, end);
                    } else {
                        // For occurrence edits, retain fields and replace the changed values.
                        value = { ...dataItem, ...value };
                    }

                    this.handleUpdate(dataItem, value, editMode);
                });
        } else {
            this.handleUpdate(dataItem, value);
        }
    }

    private seriesDate(head: Date, occurence: Date, current: Date): Date {
        const year = occurence.getFullYear() === current.getFullYear() ? head.getFullYear() : current.getFullYear();
        const month = occurence.getMonth() === current.getMonth() ? head.getMonth() : current.getMonth();
        const date = occurence.getDate() === current.getDate() ? head.getDate() : current.getDate();
        const hours = occurence.getHours() === current.getHours() ? head.getHours() : current.getHours();
        const minutes = occurence.getMinutes() === current.getMinutes() ? head.getMinutes() : current.getMinutes();

        return new Date(year, month, date, hours, minutes);
    }
```

## Reactive Forms with Resources and Grouping

When using reactive forms with grouped resources, the editing behavior remains the same, but you need to handle resource assignment within your form configuration.

```ts
public slotDblClickHandler({ sender, start, end, isAllDay, resources }: SlotClickEvent): void {
    this.closeEditor(sender);

    this.formGroup = this.formBuilder.group({
        'Start': [start, Validators.required],
        'End': [end, Validators.required],
        'StartTimezone': new FormControl(),
        'EndTimezone': new FormControl(),
        'IsAllDay': isAllDay,
        'Title': new FormControl(''),
        'Description': new FormControl(''),
        'RecurrenceRule': new FormControl(),
        'RecurrenceID': new FormControl(),
        // Add the resource fields required by your Scheduler configuration.
        'RoomId': [resources?.RoomId || null],
        'OwnerId': [resources?.OwnerId || null]
    });

    sender.addEvent(this.formGroup);
}
```

The following example demonstrates reactive forms editing with grouped resources.

[Demo Source](https://demos.telerik.com/kendo-angular-ui/demos/scheduler/editing/reactive-forms-grouping/source.txt)

## Suggested Links

* [Angular Scheduler Overview](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler)
* [Overview of Editing](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/editing)
* [Custom Editing in Reactive Forms](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/editing/custom-reactive-editing)
* [`ReactiveEditingDirective`](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/reactiveeditingdirective)
* [API Reference of the SchedulerComponent](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api/schedulercomponent)
* [API Index of the Scheduler](https://www.telerik.com/kendo-angular-ui-develop/components/scheduler/api)
