Top

Calender

With a busy schedule, users might need something to keep track of the upcoming events. A calendar app has been provided, where users can enter the upcoming events and a tag will be added in the calendar. Now you don't have to worry whether you will remember the next scheduled meeting.


Installing and usage

ng add angular-calendar

Inside Your Template tag add:

<div class="container-fluid calendar-basic">
    <div class="row">
        <div class="col-sm-12">
          <div class="card">
            <div class="card-body">
              <div class="calendar-default" id="calendar-container">
                <div class="row text-center">
                  <div class="col-md-4">
                    <div class="btn-group">
                      <div class="btn btn-primary" mwlCalendarPreviousView [view]="view" [(viewDate)]="viewDate"
                        (viewDateChange)="closeOpenMonthViewDay()"> Previous
                      </div>
                      <div class="btn btn-outline-secondary" mwlCalendarToday [(viewDate)]="viewDate"> Today</div>
                      <div class="btn btn-primary" mwlCalendarNextView [view]="view" [(viewDate)]="viewDate" (viewDateChange)="closeOpenMonthViewDay()"> Next</div>
                    </div>
                  </div>
                  <div class="col-md-4">
                    <h3>{{ viewDate | calendarDate:(view + 'ViewTitle'):'en' }}</h3>
                  </div>
                  <div class="col-md-4">
                    <div class="btn-group">
                      <div class="btn btn-primary" (click)="setView(CalendarView.Month)" [class.active]="view === CalendarView.Month"> Month</div>
                      <div class="btn btn-primary" (click)="setView(CalendarView.Week)" [class.active]="view === CalendarView.Week"> Week</div>
                      <div class="btn btn-primary" (click)="setView(CalendarView.Day)" [class.active]="view === CalendarView.Day"> Day</div>
                    </div>
                  </div>
                </div>
                <br />
                <div [ngSwitch]="view">
                  <mwl-calendar-month-view *ngSwitchCase="CalendarView.Month" [viewDate]="viewDate" [events]="events" [refresh]="refresh" [activeDayIsOpen]="activeDayIsOpen" (dayClicked)="dayClicked($event.day)" (eventClicked)="handleEvent('Clicked', $event.event)" (eventTimesChanged)="eventTimesChanged($event)"></mwl-calendar-month-view>
                  <mwl-calendar-week-view *ngSwitchCase="CalendarView.Week" [viewDate]="viewDate" [events]="events" [refresh]="refresh" (eventClicked)="handleEvent('Clicked', $event.event)" (eventTimesChanged)="eventTimesChanged($event)"></mwl-calendar-week-view>
                  <mwl-calendar-day-view *ngSwitchCase="CalendarView.Day" [viewDate]="viewDate" [events]="events" [refresh]="refresh" (eventClicked)="handleEvent('Clicked', $event.event)" (eventTimesChanged)="eventTimesChanged($event)"></mwl-calendar-day-view>
                </div>
                <br /><br /><br />
                <h3>
                  Edit events
                  <button class="btn btn-primary float-end" (click)="addEvent()">Add new</button>
                  <div class="clearfix"></div>
                </h3>
                <div class="table-responsive mt-4 theme-scrollbar">
                  <table class="table table-bordered">
                    <thead>
                      <tr>
                        <th>Title</th>
                        <th>Primary color</th>
                        <th>Secondary + text color</th>
                        <th>Starts at</th>
                        <th>Ends at</th>
                        <th>Remove</th>
                      </tr>
                    </thead>
                    <tbody>
                      <tr *ngFor="let event of events">
                        <td>
                          <input type="text" class="form-control" [(ngModel)]="event.title" (keyup)="refresh.next()" />
                        </td>
                        <td *ngIf="event.color">
                          <input type="color" [(ngModel)]="event.color.primary" (change)="refresh.next()" />
                        </td>
                        <td *ngIf="event.color">
                          <input type="color" [(ngModel)]="event.color.secondary" (change)="refresh.next()" />
                          <input type="color" [ngModel]="event.color.secondaryText ?? '#1e90ff'" (ngModelChange)="event.color.secondaryText = $event" (change)="refresh.next()" />
                        </td>
                        <td>
                          <input class="form-control" type="text" mwlFlatpickr [(ngModel)]="event.start" (ngModelChange)="refresh.next()" [altInput]="true" [convertModelValue]="true" [enableTime]="true" dateFormat="Y-m-dTH:i" altFormat="F j, Y H:i" placeholder="Not set" />
                        </td>
                        <td>
                          <input class="form-control" type="text" mwlFlatpickr [(ngModel)]="event.end" (ngModelChange)="refresh.next()" [altInput]="true" [convertModelValue]="true" [enableTime]="true" dateFormat="Y-m-dTH:i" altFormat="F j, Y H:i" placeholder="Not set" />
                        </td>
                        <td>
                          <button class="btn btn-danger" (click)="deleteEvent(event)">Delete</button>
                        </td>
                      </tr>
                    </tbody>
                  </table>
                </div>
                <ng-template #modalContent let-close="close">
                  <div class="modal-header">
                    <h5 class="modal-title">Event action occurred</h5>
                    <button type="button" class="close" (click)="close()">
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>
                  <div class="modal-body">
                    <div>Action:<pre>{{ modalData.action }}</pre></div>
                    <div>Event:<pre>{{ modalData.event | json }}</pre></div>
                  </div>
                  <div class="modal-footer">
                    <button type="button" class="btn btn-outline-secondary" (click)="close()">OK</button>
                  </div>
                </ng-template>
              </div>
            </div>
          </div>
        </div>
      </div>
  </div>

Inside Your Script tag add:


import { CommonModule } from '@angular/common';
import { Component, inject, TemplateRef, viewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { NgbModule, NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
  CalendarA11y,
  CalendarDateFormatter,
  CalendarEventTitleFormatter,
  CalendarModule,
  CalendarUtils,
  CalendarEvent,
  CalendarEventAction,
  CalendarEventTimesChangedEvent,
  CalendarView,
} from 'angular-calendar';
import { FlatpickrDefaults, FlatpickrModule } from 'angularx-flatpickr';
import { EventColor } from 'calendar-utils';
import {
  startOfDay,
  endOfDay,
  subDays,
  addDays,
  endOfMonth,
  isSameDay,
  isSameMonth,
  addHours,
} from 'date-fns';
import { Subject } from 'rxjs';

const colors: Record = {
  red: {
    primary: '#6f5a99',
    secondary: '#E0DDFF',
  },
  blue: {
    primary: '#1868ae',
    secondary: '#D1E8FF',
  },
  yellow: {
    primary: '#D77748',
    secondary: '#fbdac9',
  },
};

@Component({
  selector: 'app-calendar',
  templateUrl: './calendar.html',
  styleUrls: ['./calendar.scss'],
  imports: [CommonModule, NgbModule, FormsModule, CalendarModule, FlatpickrModule],
  providers: [
    CalendarDateFormatter,
    CalendarUtils,
    FlatpickrDefaults,
    CalendarA11y,
    CalendarEventTitleFormatter,
  ],
})
export class Calendar {
  readonly modalContent = viewChild>('modalContent');

  public view: CalendarView = CalendarView.Month;
  public CalendarView = CalendarView;
  public viewDate: Date = new Date();
  public activeDayIsOpen: boolean = true;
  public color: string;
  public modalData: {
    action: string;
    event: CalendarEvent;
  };

  public actions: CalendarEventAction[] = [
    {
      label: '',
      a11yLabel: 'Edit',
      onClick: ({ event }: { event: CalendarEvent }): void => {
        this.handleEvent('Edited', event);
      },
    },
    {
      label: '',
      a11yLabel: 'Delete',
      onClick: ({ event }: { event: CalendarEvent }): void => {
        this.events = this.events.filter(iEvent => iEvent !== event);
        this.handleEvent('Deleted', event);
      },
    },
  ];

  public refresh = new Subject();

  public events: CalendarEvent[] = [
    {
      start: subDays(startOfDay(new Date()), 1),
      end: addDays(new Date(), 1),
      title: 'A 3 day event',
      color: { ...colors['red'] },
      actions: this.actions,
      allDay: true,
      resizable: {
        beforeStart: true,
        afterEnd: true,
      },
      draggable: true,
    },
    {
      start: startOfDay(new Date()),
      title: 'An event with no end date',
      color: { ...colors['yellow'] },
      actions: this.actions,
    },
    {
      start: subDays(endOfMonth(new Date()), 3),
      end: addDays(endOfMonth(new Date()), 3),
      title: 'A long event that spans 2 months',
      color: { ...colors['blue'] },
      allDay: true,
    },
    {
      start: addHours(startOfDay(new Date()), 2),
      end: addHours(new Date(), 2),
      title: 'A draggable and resizable event',
      color: { ...colors['yellow'] },
      actions: this.actions,
      resizable: {
        beforeStart: true,
        afterEnd: true,
      },
      draggable: true,
    },
  ];

  public modal = inject(NgbModal);

  dayClicked({ date, events }: { date: Date; events: CalendarEvent[] }): void {
    if (isSameMonth(date, this.viewDate)) {
      if (
        (isSameDay(this.viewDate, date) && this.activeDayIsOpen === true) ||
        events.length === 0
      ) {
        this.activeDayIsOpen = false;
      } else {
        this.activeDayIsOpen = true;
      }
      this.viewDate = date;
    }
  }

  eventTimesChanged({ event, newStart, newEnd }: CalendarEventTimesChangedEvent): void {
    this.events = this.events.map(iEvent => {
      if (iEvent === event) {
        return {
          ...event,
          start: newStart,
          end: newEnd,
        };
      }
      return iEvent;
    });
    this.handleEvent('Dropped or resized', event);
  }

  handleEvent(action: string, event: CalendarEvent): void {
    this.modalData = { event, action };
    this.modal.open(this.modalContent(), { size: 'lg' });
  }

  addEvent(): void {
    this.events = [
      ...this.events,
      {
        title: 'New event',
        start: startOfDay(new Date()),
        end: endOfDay(new Date()),
        color: colors['red'],
        draggable: true,
        resizable: {
          beforeStart: true,
          afterEnd: true,
        },
      },
    ];
  }

  deleteEvent(eventToDelete: CalendarEvent) {
    this.events = this.events.filter(event => event !== eventToDelete);
  }

  setView(view: CalendarView) {
    this.view = view;
  }

  closeOpenMonthViewDay() {
    this.activeDayIsOpen = false;
  }
}