# 이벤트 생성, 편집 및 삭제

## Content

사용자가 직접 CRUD 작업을 수행하는 경우 기본 제공 편집기를 사용하거나 애플리케이션 코드에서 바인딩된 컬렉션을 업데이트할 수 있습니다. 변경 사항을 저장하기 전에 제안된 값을 검증하고, 승인된 변경 사항은 컬렉션 또는 서비스 계층을 통해 저장합니다.

## 기본 제공 편집기 사용

빈 셀을 더블 클릭하면 새 이벤트를 만들 수 있으며, 기존 이벤트를 더블 클릭하면 편집할 수 있습니다. 저장을 선택하면 스케줄러의 CRUD 처리 과정에 따라 변경 사항이 제출됩니다. 취소를 선택하면 원본 항목을 변경하지 않고 편집기가 닫힙니다.

| 편집기 모드 | 초기값 | 삭제 버튼 | 예시 |
| ------ | --- | ----- | --- |
| 셀에서 생성 | 대상 셀의 시작 시간, 종료 시간 및 리소스 값. 제목과 설명은 비어 있음 | 숨김 | ![셀생성](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/8ecc18d2-feec-4d15-bd72-3d98a7b4cefa/9-1-20261019.7927e5.png) |
| 이벤트 편집 | 원본 항목의 제목, 시작 시간, 종료 시간, 설명 및 리소스 값 | 표시 | ![이벤트편집](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/8ecc18d2-feec-4d15-bd72-3d98a7b4cefa/9-2-20261019.12822c.png) |

편집기에서 이벤트를 저장하려면 유효한 시작 시간과 종료 시간이 필요하며, 종료 시간은 시작 시간보다 늦어야 합니다. 제목, 설명 및 리소스 값은 구성된 이벤트 필드와 리소스 설명자에서 가져옵니다. 제목이 없으면 현지화된 기본 제목이 사용됩니다.

기본적으로 리소스 필드는 하나의 값만 지원합니다. `allowMultiple: true`로 설정된 리소스 설명자는 선택한 값을 배열로 저장합니다.
각 리소스 설명자는 `dataSource`, `displayExpr`, `valueExpr`를 사용해 편집기에 해당 리소스 필드를 생성합니다. 접근성 이름은 `label`에 지정하며, 생략하면 현지화된 `Resource` 레이블이 사용됩니다.

저장을 선택하면 편집기가 입력값을 검증합니다. 유효하지 않은 필드에는 현지화된 오류 메시지가 표시되고, 포커스가 첫 번째 유효하지 않은 필드로 이동합니다. 오류가 해결될 때까지 편집기는 열린 상태로 유지됩니다.
시작 시간과 종료 시간은 필수이며, 종료 시간은 시작 시간보다 늦어야 합니다. 리소스 필드는 기본적으로 하나의 값만 허용합니다. `allowMultiple`을 생략하거나 `false`로 설정한 경우 여러 값을 선택하면 저장이 차단되고 유효성 검사 오류가 표시됩니다. 여러 값을 허용하려면 `allowMultiple: true`로 설정하세요. 이 경우 선택한 값이 배열로 저장됩니다.

## 변경 사항 검증

권한 및 비즈니스 규칙을 검증하려면 `itemChanging`을 사용합니다. 변경 사항을 커밋하기 전에 이벤트 간 중복이나 작업 시간 충돌을 검사하려면 `conflictChecked`를 사용합니다.

```ts
scheduler.itemChanging.addHandler((_sender, args) => {
  if (!canEdit(args.request.item)) {
    args.cancel = true;
  }
});

scheduler.conflictChecked.addHandler((_sender, args) => {
  const conflicts = args.result?.conflicts ?? [];
  if (conflicts.length > 0 && !allowConflicts) {
    args.cancel = true;
  }
});
```

두 이벤트 중 하나에서 작업을 취소하면 바인딩된 원본 항목은 변경되지 않으며, 편집기 또는 상호 작용은 취소된 상태로 유지됩니다. 충돌 결과에 대한 자세한 내용은 [충돌 감지 및 처리](/wijmo/docs/Topics/----/---------)를 참조하세요.

## 승인된 변경 사항 저장

스케줄러가 생성, 수정 또는 삭제 요청을 승인한 후 `itemChanged`가 발생합니다. 이 이벤트를 사용하여 변경된 원본 항목을 서버에 저장할 수 있습니다.

이 이벤트 핸들러는 비동기 작업의 완료를 기다리지 않습니다. 스케줄러는 `addHandler` 콜백이 반환하는 Promise를 기다리지 않으며, `itemChanged` 이벤트가 발생할 때는 로컬 컬렉션의 변경이 이미 완료된 상태입니다. 여러 편집 요청이 동시에 제출될 수 있다면, 응답이 최신 변경 사항을 덮어쓰지 않도록 애플리케이션에서 요청 순서를 관리하거나 서버 측 버전 검사를 사용하세요.

```ts
scheduler.itemChanged.addHandler(async (_sender, args) => {
  const item = args.result.item;
  try {
    switch (args.result.action) {
      case wjScheduler.SchedulerItemChangeAction.Create:
      case wjScheduler.SchedulerItemChangeAction.Update:
        await api.saveEvent(item);
        break;
      case wjScheduler.SchedulerItemChangeAction.Remove:
        await api.deleteEvent(item);
        break;
    }
  } catch (error) {
    await reloadEvents();
  }
});
```

스케줄러는 서버 측 유효성 검사를 대신하지 않습니다. `itemChanged` 이벤트가 발생하면 로컬 변경 사항은 이미 적용된 상태입니다. 저장에 실패하면 바인딩된 컬렉션을 다시 불러오거나 별도의 조정 작업을 수행해야 합니다. 이 과정은 애플리케이션에서 직접 처리해야 하며, 자동으로 롤백되지는 않습니다.

## 프로그래밍 방식으로 이벤트 생성, 수정 및 삭제

변경 사항이 스케줄러의 CRUD 처리 과정을 거쳐야 한다면 스케줄러의 CRUD 메서드를 사용하세요. 이 메서드는 `itemChanging` 이벤트를 발생시키고 충돌을 검사한 다음, 원본 컬렉션을 업데이트하고 `itemChanged` 이벤트를 발생시킵니다.

```ts
events.addNew({
  subject: 'Review',
  start: new Date(2026, 7, 24, 11),
  end: new Date(2026, 7, 24, 12),
});

if (created.item) {
  scheduler.update(created.item, { subject: 'Final review' });
  scheduler.remove(created.item);
}
```

기존 이벤트를 수정하거나 삭제하려면 컬렉션에서 원본 항목을 가져와 동일한 객체 참조를 전달합니다.

```ts
const [event] = scheduler.getEvents(
  new Date(2026, 7, 24),
  new Date(2026, 7, 25)
);

if (event) {
  scheduler.update(event, { subject: 'Final review' });
  scheduler.remove(event);
}
```

각 메서드는 작업의 성공 여부와 영향을 받은 항목을 포함하는 결과를 반환합니다.

### 바인딩된 컬렉션 직접 업데이트

서버에서 데이터를 새로 불러오거나 다른 컨트롤에서 변경하는 등 스케줄러 외부에서 변경이 발생한 경우에는 바인딩된 `CollectionView`를 직접 수정하는 것이 적합합니다. 스케줄러는 변경된 컬렉션을 다시 렌더링하지만, 이 과정에서는 스케줄러의 CRUD 이벤트가 발생하지 않으며 충돌 검사도 수행되지 않습니다.

```ts
events.addNew({
  subject: 'Review',
  start: new Date(2026, 7, 24, 11),
  end: new Date(2026, 7, 24, 12),
});
events.commitNew();
```

화면에 표시된 이벤트 조각을 직접 수정하지 마세요. 하나의 원본 이벤트가 여러 날짜나 리소스 영역에 나뉘어 표시될 수 있습니다. 원본 항목을 수정하면 모든 조각에 변경 사항이 일관되게 반영됩니다.

## CRUD 수명 주기

| 단계 | 이벤트 | 취소 가능 | 목적 |
| --- | --- | ----- | --- |
| 요청 시작 | `itemChanging` | 예 | 권한 및 애플리케이션 유효성 검사 |
| 후보 검증 | `conflictChecked` | 예 | 충돌을 검사하고 필요에 따라 거부 |
| 요청 승인 | `itemChanged` | 아니요 | 원본 컬렉션 저장 또는 조정 |

`itemChanging`에서 취소하면 충돌 감지가 실행되기 전에 요청이 중단됩니다. `conflictChecked`에서 취소하면 컬렉션이 업데이트되기 전에 변경 후보가 거부됩니다. `itemChanged`는 로컬 원본 컬렉션이 성공적으로 업데이트되었음을 의미하지만, 서버 저장 성공을 의미하지는 않습니다. 후보 및 결과의 구체적인 속성은 API 참조 문서에 정의되어 있습니다.