Features
Uses DayPilot Angular Scheduler component for scheduling events for multiple resources
Uses DayPilotModalComponent component to create customized modal dialog.
"Create Event" modal dialog is used to enter details of a new event (after selecting a time range in the Scheduler)
"Update Event" modal dialgo is used to modify existing Scheduler events (opened upon event click or using a context menu)
The project uses Angular 6 and Angular CLI 6.0
Includes a trial version of DayPilot Pro for JavaScript
This tutorial doesn't cover Scheduler basics (installation, configuration). For an introduction to DayPilot Scheduler and Angular, please see the following tutorial:
License
Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript.
Live Demo
You can test this project in a live demo:
Angular Modal Dialog
DayPilot includes a special Angular version of the modal dialog. The pure JavaScript DayPilot.Modal dialog can't be used because it requires access to the DOM at the top level which doesn't work well with Angular.
It has a different appearance and behavior - the Angular version slides down from the top of the page and always uses full page width. This makes it more compatible with mobile devices with small screen.
Creating New Events in the Scheduler
Handle onTimeRangeSelected event and use it to open the modal dialog.
"Create Event" Modal Dialog
scheduler.component.ts
import {Component, ViewChild, AfterViewInit, ChangeDetectorRef} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";
import {CreateComponent} from "./create.component";
import {EditComponent} from "./edit.component";
@Component({
selector: 'scheduler-component',
template: `
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
<create-dialog #create (close)="createClosed($event)"></create-dialog>
...
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild("scheduler") scheduler: DayPilotSchedulerComponent;
@ViewChild("create") create: CreateComponent;
// ...
config: any = {
// ...
onTimeRangeSelected: args => {
this.create.show(args);
}
// ...
};
// ...
createClosed(args) {
if (args.result) {
this.events.push(args.result);
this.scheduler.control.message("Created.");
}
this.scheduler.control.clearSelection();
}
// ...
}
create.component.ts
import {Component, ViewChild, Output, EventEmitter} from '@angular/core';
import {DayPilot, DayPilotModalComponent} from "daypilot-pro-angular";
import {Validators, FormBuilder, FormGroup, FormControl} from "@angular/forms";
import {DataService, CreateEventParams} from "./data.service";
@Component({
selector: 'create-dialog',
template: `
<daypilot-modal #modal (close)="closed($event)">
<div class="center">
<h1>Create Event</h1>
<form [formGroup]="form">
<div class="form-item">
<input formControlName="name" type="text" placeholder="Event Name"> <span *ngIf="!form.controls.name.valid">Event name required</span>
</div>
<div class="form-item">
<select formControlName="resource">
<option *ngFor="let r of resources" [ngValue]="r.id">{{r.name}}</option>
</select>
</div>
<div class="form-item">
<input formControlName="start" type="text" placeholder="Start"> <span *ngIf="!form.controls.start.valid">Invalid datetime</span>
</div>
<div class="form-item">
<input formControlName="end" type="text" placeholder="End"> <span *ngIf="!form.controls.end.valid">Invalid datetime</span>
</div>
<div class="form-item">
<button (click)="submit()" [disabled]="!form.valid">Create</button>
<button (click)="cancel()">Cancel</button>
</div>
</form>
</div>
</daypilot-modal>
`,
styles: [`
.center {
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.form-item {
margin: 4px 0px;
}
`]
})
export class CreateComponent {
@ViewChild("modal") modal : DayPilotModalComponent;
@Output() close = new EventEmitter();
form: FormGroup;
dateFormat = "MM/dd/yyyy h:mm tt";
resources: any[];
constructor(private fb: FormBuilder, private ds: DataService) {
this.form = this.fb.group({
name: ["", Validators.required],
start: ["", this.dateTimeValidator(this.dateFormat)],
end: ["", [Validators.required, this.dateTimeValidator(this.dateFormat)]],
resource: ["", Validators.required]
});
this.ds.getResources().subscribe(result => this.resources = result);
}
show(args: any) {
args.name = "";
this.form.setValue({
start: args.start.toString(this.dateFormat),
end: args.end.toString(this.dateFormat),
name: "",
resource: args.resource
});
this.modal.show();
}
submit() {
let data = this.form.getRawValue();
let params: CreateEventParams = {
start: DayPilot.Date.parse(data.start, this.dateFormat).toString(),
end: DayPilot.Date.parse(data.end, this.dateFormat).toString(),
text: data.name,
resource: data.resource
};
this.ds.createEvent(params).subscribe(result => {
//params.id = result.id;
this.modal.hide(result);
});
}
cancel() {
this.modal.hide();
}
closed(args) {
this.close.emit(args);
}
dateTimeValidator(format: string) {
return function(c:FormControl) {
let valid = !!DayPilot.Date.parse(c.value, format);
return valid ? null : {badDateTimeFormat: true};
};
}
}
When the modal dialog is closed the events is updated and control is passed back to the SchedulerComponent.
It displays a message:
"Update Event" Modal Dialog
scheduler.component.ts
import {Component, ViewChild, AfterViewInit, ChangeDetectorRef} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";
import {CreateComponent} from "./create.component";
import {EditComponent} from "./edit.component";
@Component({
selector: 'scheduler-component',
template: `
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
...
<edit-dialog #edit (close)="editClosed($event)"></edit-dialog>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild("scheduler") scheduler: DayPilotSchedulerComponent;
//...
@ViewChild("edit") edit: EditComponent;
config: any = {
// ...
onEventClicked: args => {
this.edit.show(args.e);
},
// ...
};
// ...
editClosed(args) {
if (args.result) {
this.scheduler.control.message("Updated");
}
}
// ...
}
edit.component.ts
import {Component, ViewChild, Output, EventEmitter} from '@angular/core';
import {DayPilot, DayPilotModalComponent} from "daypilot-pro-angular";
import {Validators, FormBuilder, FormGroup, FormControl} from "@angular/forms";
import {DataService, CreateEventParams, EventData, UpdateEventParams} from "./data.service";
@Component({
selector: 'edit-dialog',
template: `
<daypilot-modal #modal (close)="closed($event)">
<div class="center">
<h1>Update Event</h1>
<form [formGroup]="form">
<div class="form-item">
<input formControlName="name" type="text" placeholder="Event Name"> <span *ngIf="!form.controls.name.valid">Event name required</span>
</div>
<div class="form-item">
<select formControlName="resource">
<option *ngFor="let r of resources" [ngValue]="r.id">{{r.name}}</option>
</select>
</div>
<div class="form-item">
<input formControlName="start" type="text" placeholder="Start"> <span *ngIf="!form.controls.start.valid">Invalid datetime</span>
</div>
<div class="form-item">
<input formControlName="end" type="text" placeholder="End"> <span *ngIf="!form.controls.end.valid">Invalid datetime</span>
</div>
<div class="form-item">
<button (click)="submit()" [disabled]="!form.valid">Create</button>
<button (click)="cancel()">Cancel</button>
</div>
</form>
</div>
</daypilot-modal>
`,
styles: [`
.center {
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.form-item {
margin: 4px 0px;
}
`]
})
export class EditComponent {
@ViewChild("modal") modal : DayPilotModalComponent;
@Output() close = new EventEmitter();
form: FormGroup;
dateFormat = "MM/dd/yyyy h:mm tt";
resources: any[];
event: DayPilot.Event;
constructor(private fb: FormBuilder, private ds: DataService) {
this.form = this.fb.group({
name: ["", Validators.required],
start: ["", this.dateTimeValidator(this.dateFormat)],
end: ["", [Validators.required, this.dateTimeValidator(this.dateFormat)]],
resource: ["", Validators.required]
});
this.ds.getResources().subscribe(result => this.resources = result);
}
show(ev: DayPilot.Event) {
this.event = ev;
this.form.setValue({
start: ev.start().toString(this.dateFormat),
end: ev.end().toString(this.dateFormat),
name: ev.text(),
resource: ev.resource()
});
this.modal.show();
}
submit() {
let data = this.form.getRawValue();
// modify the original object from [events] which is stored in event.data
this.event.data.start = DayPilot.Date.parse(data.start, this.dateFormat);
this.event.data.end = DayPilot.Date.parse(data.end, this.dateFormat);
this.event.data.resource = data.resource;
this.event.data.text = data.name;
this.ds.updateEvent(this.event).subscribe(result => {
this.modal.hide(result);
});
}
cancel() {
this.modal.hide();
}
closed(args) {
this.close.emit(args);
}
dateTimeValidator(format: string) {
return function(c:FormControl) {
let valid = !!DayPilot.Date.parse(c.value, format);
return valid ? null : {badDateTimeFormat: true};
};
}
}
Context Menu
The same approach can be used to open the "Update Event" modal dialog using an event context menu.
scheduler.component.ts
import {Component, ViewChild, AfterViewInit, ChangeDetectorRef} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";
import {CreateComponent} from "./create.component";
import {EditComponent} from "./edit.component";
@Component({
selector: 'scheduler-component',
template: `
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
...
<edit-dialog #edit (close)="editClosed($event)"></edit-dialog>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild("scheduler") scheduler: DayPilotSchedulerComponent;
// ...
@ViewChild("edit") edit: EditComponent;
events: any[] = [];
config: any = {
// ...
contextMenu: new DayPilot.Menu({
items: [
{ text: "Edit", onClick: args => this.edit.show(args.source) },
]
}),
// ...
};
editClosed(args) {
if (args.result) {
this.scheduler.control.message("Updated");
}
}
}