Build Ionic 3 Angular 5 Calendar UI with Event Integration

by Didin J. on Nov 15, 2017 Build Ionic 3 Angular 5 Calendar UI with Event Integration

Step by step tutorial of building your own calendar UI with native event integration using Ionic 3, Angular 5, and native Cordova calendar plugin

This step by step tutorial describes how to build your own calendar UI with event integration using Ionic 3, Angular 5, and native Cordova calendar plugin. There is a lot of Angular calendar UI module, but we will not using one of them because that's easy to make our own calendar UI using Ionic 3 and Angular 5 from scratch. For event integration, we are using this Ionic 3 and Cordova native plugin.

Jumps to the steps:

So, the following modules, plugin, framework, and tools are required to achieve this tutorial goal:

  1. Node.js (recommended stable version)
  2. Ionic 3
  3. Angular 5
  4. Cordova
  5. Ionic 3 Cordova Native Calendar Plugin
  6. IDE or Text Editor
  7. Terminal or Node Command Line

We assume that you already installed Node.js and can run `npm` on the terminal (Mac OS/Linux) or Node.js command line (Windows). Now, update or install Ionic 3 and Cordova with the latest version. The open terminal then goes to your Ionic 3 projects folder then type this command.

sudo npm i -D -E ionic@latest
sudo npm i cordova


Create a New Ionic 3, Angular 5 App

On the terminal or Node.js command line type this command to create a new Ionic 3, Angular 5 and Cordova App.

ionic start mycalendar blank

Go to your newly created project folder by type this command.

cd ./mycalendar

For tutorial sanitation, run the app on the browser then type this command.

ionic serve -l

As usual, you will see this page in the default browser.

Build Ionic 3 Angular 5 Calendar UI with Event Integration - Ionic 3 blank


Create Calendar UI from Scratch

Now, let's get your hand dirty. We will create our own calendar UI or view from scratch. This basic calendar will very simple, it just Month header with previous and next month button. Now, open and edit `src/pages/home/home.ts` then add these variables to the constructor.

date: any;
daysInThisMonth: any;
daysInLastMonth: any;
daysInNextMonth: any;
monthNames: string[];
currentMonth: any;
currentYear: any;
currentDate: any;

Next, create the function for push calendar date items to the arrays that will be displaying the full calendar date.

getDaysOfMonth() {
  this.daysInThisMonth = new Array();
  this.daysInLastMonth = new Array();
  this.daysInNextMonth = new Array();
  this.currentMonth = this.monthNames[this.date.getMonth()];
  this.currentYear = this.date.getFullYear();
  if(this.date.getMonth() === new Date().getMonth()) {
    this.currentDate = new Date().getDate();
  } else {
    this.currentDate = 999;
  }

  var firstDayThisMonth = new Date(this.date.getFullYear(), this.date.getMonth(), 1).getDay();
  var prevNumOfDays = new Date(this.date.getFullYear(), this.date.getMonth(), 0).getDate();
  for(var i = prevNumOfDays-(firstDayThisMonth-1); i <= prevNumOfDays; i++) {
    this.daysInLastMonth.push(i);
  }

  var thisNumOfDays = new Date(this.date.getFullYear(), this.date.getMonth()+1, 0).getDate();
  for (var i = 0; i < thisNumOfDays; i++) {
    this.daysInThisMonth.push(i+1);
  }

  var lastDayThisMonth = new Date(this.date.getFullYear(), this.date.getMonth()+1, 0).getDay();
  var nextNumOfDays = new Date(this.date.getFullYear(), this.date.getMonth()+2, 0).getDate();
  for (var i = 0; i < (6-lastDayThisMonth); i++) {
    this.daysInNextMonth.push(i+1);
  }
  var totalDays = this.daysInLastMonth.length+this.daysInThisMonth.length+this.daysInNextMonth.length;
  if(totalDays<36) {
    for(var i = (7-lastDayThisMonth); i < ((7-lastDayThisMonth)+7); i++) {
      this.daysInNextMonth.push(i);
    }
  }
}

Now, add the function for previous month button action.

goToLastMonth() {
  this.date = new Date(this.date.getFullYear(), this.date.getMonth(), 0);
  this.getDaysOfMonth();
}

Also for the next month button action.

goToNextMonth() {
  this.date = new Date(this.date.getFullYear(), this.date.getMonth()+2, 0);
  this.getDaysOfMonth();
}

Next, open and edit `src/pages/home/home.html` then simply replace all HTML tags with this few lines of HTML tags.

<ion-header>
  <ion-navbar>
    <ion-title>
      My Calendar App
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <div class="calendar-header">
    <ion-row class="calendar-month">
      <ion-col col-2 (click)="goToLastMonth()"><ion-icon name="arrow-back"></ion-icon></ion-col>
      <ion-col col-8>{{currentMonth}} {{currentYear}}</ion-col>
      <ion-col col-2 (click)="goToNextMonth()"><ion-icon name="arrow-forward"></ion-icon></ion-col>
    </ion-row>
  </div>
  <div class="calendar-body">
    <ion-grid>
      <ion-row class="calendar-weekday">
        <ion-col>Su</ion-col>
        <ion-col>Mo</ion-col>
        <ion-col>Tu</ion-col>
        <ion-col>We</ion-col>
        <ion-col>Th</ion-col>
        <ion-col>Fr</ion-col>
        <ion-col>Sa</ion-col>
      </ion-row>
      <ion-row class="calendar-date">
        <ion-col col-1 *ngFor="let lastDay of daysInLastMonth" class="last-month">{{lastDay}}</ion-col>
        <ion-col col-1 *ngFor="let day of daysInThisMonth">
          <span class="currentDate" *ngIf="currentDate === day; else otherDate">{{day}}</span>
          <ng-template #otherDate class="otherDate">{{day}}</ng-template>
        </ion-col>
        <ion-col col-1 *ngFor="let nextDay of daysInNextMonth" class="next-month">{{nextDay}}</ion-col>
      </ion-row>
    </ion-grid>
  </div>
</ion-content>

Now, we have to give it a little cosmetics. Open and edit `src/pages/home/home.scss` then add these lines of a CSS style.

page-home {
  [col-1] {
    -webkit-box-flex: 0;
    -webkit-flex: 0 0 8.33333%;
    -ms-flex: 0 0 8.33333%;
    flex: 0 0 14.285714285714286%;
    width: 14.285714285714286%;
    max-width: 14.285714285714286%;
  }
  .col {
    text-align: center;
    padding: 5px;
  }
  .last-month, .next-month {
    color: #999999;
    font-size: 90%;
  }
  .currentDate, .otherDate {
    padding: 5px;
  }
  .currentDate {
    font-weight: bold;
    background-color: red;
    color: white;
    border-radius: 30px;
  }
  .calendar-header {
    background-color: #1a732d;
    color: #FFFFFF;
  }
  .event-bullet {
    margin: 2px auto;
    height: 5px;
    width: 5px;
    background-color: green;
    border-radius: 30px;
  }
  .selected-date {
    width: 20px;
    height: 2px;
    background-color: blue;
  }
  .unselected-date {
    border: none;
  }
  .calendar-body {
    .grid {
      padding: 0;
    }
    .col:last-child {
      border-right: none;
    }
    .calendar-weekday, .calendar-date {
      text-align: center;
      margin: 0;
    }
    .calendar-weekday {
      font-weight: bold;
      border-bottom: solid 1px #1a732d;
      background-color: #26ab56;
    }
    .calendar-date {
      border-top: solid 1px #1a732d;
      border-bottom: solid 1px #1a732d;
    }
  }
}

That's it, your own simple calendar is ready for some action that will create later. Now, test your own calendar UI by run the Ionic 3 Angular 5 app on the browser.

ionic serve -l

Here it is.

Build Ionic 3 Angular 5 Calendar UI with Event Integration - Ionic 3 Angular 5 Calendar UI


Install and Configure Native Ionic Cordova Calendar Plugin

To integrate the calendar with native Ionic 3 Cordova calendar plugin, type this command to install it first.

ionic cordova plugin add cordova-plugin-calendar
npm install --save @ionic-native/calendar

Now, open and edit `src/app/app.module.ts` then add this import of Calendar.

import { Calendar } from '@ionic-native/calendar';

Add `Calendar` module to `@NgModule` providers.

providers: [
  StatusBar,
  SplashScreen,
  {provide: ErrorHandler, useClass: IonicErrorHandler},
  Calendar
]

Now, it's ready to implement in the pages.


Create a Page for Add Event

To add an event to the calendar we have to create a new page that contains a form of event. Type this command to create a new Ionic 3 page.

ionic g page AddEvent

Register this new page to `src/app/app.module.ts` by adding this import first AddEventPage.

import { AddEventPage } from '../pages/add-event/add-event';

Add the `AddEventPage` to `@NgModule` imports and `entryComponents`.

entryComponents: [
  MyApp,
  HomePage,
  AddEventPage
],

Before adding a form to the new page, add button first to the home page for opening the new page. Open and edit `src/pages/home/home` then add this lines of tags on the `<ion-navbar>` after `<ion-title>`.

<ion-header>
  <ion-navbar>
    <ion-title>
      My Calendar App
    </ion-title>
    <ion-buttons end>
      <button ion-button icon-only (click)="addEvent()">
        <ion-icon name="add-circle"></ion-icon>
      </button>
    </ion-buttons>
  </ion-navbar>
</ion-header>

Open and edit `src/pages/home/home.ts` then add this import of AddEventPage.

import { AddEventPage } from '../add-event/add-event';

Add this function for open event form page.

addEvent() {
  this.navCtrl.push(AddEventPage);
}


Create Form in Add Event Page

Open and edit `src/pages/add-event/add-event.html` then add these lines of tags inside `<ion-content>` tag.

<ion-content padding>
  <form (ngSubmit)="save()">
    <ion-list>
      <ion-item>
        <ion-label floating>Title</ion-label>
        <ion-input type="text" [(ngModel)]="event.title" name="event.title"></ion-input>
      </ion-item>
      <ion-item>
        <ion-label floating>Location</ion-label>
        <ion-input type="text" [(ngModel)]="event.location" name="event.location"></ion-input>
      </ion-item>
      <ion-item>
        <ion-label floating>Notes</ion-label>
        <ion-input type="text" [(ngModel)]="event.message" name="event.message"></ion-input>
      </ion-item>
      <ion-item>
        <ion-label floating>Start Date</ion-label>
        <ion-datetime displayFormat="DD MMM YYYY" pickerFormat="MM/DD/YYYY" [(ngModel)]="event.startDate" name="event.startDate"></ion-datetime>
      </ion-item>
      <ion-item>
        <ion-label floating>End Date</ion-label>
        <ion-datetime displayFormat="DD MMM YYYY" pickerFormat="MM/DD/YYYY" [(ngModel)]="event.endDate" name="event.endDate"></ion-datetime>
      </ion-item>
      <ion-item>
        <button ion-button type="submit" full round>Save</button>
      </ion-item>
    </ion-list>
  </form>
</ion-content>

Now, open and edit `src/pages/add-event/add-event.ts` then replace and add these imports.

import { IonicPage, NavController, NavParams, AlertController } from 'ionic-angular';
import { Calendar } from '@ionic-native/calendar';

Inject calendar and alert into the constructor.

constructor(public alertCtrl: AlertController,
  public navCtrl: NavController,
  public navParams: NavParams,
  private calendar: Calendar) {
}

Add a variable for holding the event object before the constructor.

event = { title: "", location: "", message: "", startDate: "", endDate: "" };

Next, create a function for saving the event.

save() {
  this.calendar.createEvent(this.event.title, this.event.location, this.event.message, new Date(this.event.startDate), new Date(this.event.endDate)).then(
    (msg) => {
      let alert = this.alertCtrl.create({
        title: 'Success!',
        subTitle: 'Event saved successfully',
        buttons: ['OK']
      });
      alert.present();
      this.navCtrl.pop();
    },
    (err) => {
      let alert = this.alertCtrl.create({
        title: 'Failed!',
        subTitle: err,
        buttons: ['OK']
      });
      alert.present();
    }
  );
}


Add Events to Calendar UI

To add events to calendar UI, open and edit again `src/pages/home/home.ts` then modify and add these imports of NavController, AlertController, and Calendar.

import { NavController, AlertController } from 'ionic-angular';
import { Calendar } from '@ionic-native/calendar';

Add these variables for hold and populate events.

eventList: any;
selectedEvent: any;
isSelected: any;

Inject the calendar native plugin to the constructor.

constructor(private alertCtrl: AlertController,
  public navCtrl: NavController,
  private calendar: Calendar) {}

Add this function to load all events in the current month.

loadEventThisMonth() {
  this.eventList = new Array();
  var startDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1);
  var endDate = new Date(this.date.getFullYear(), this.date.getMonth()+1, 0);
  this.calendar.listEventsInRange(startDate, endDate).then(
    (msg) => {
      msg.forEach(item => {
        this.eventList.push(item);
      });
    },
    (err) => {
      console.log(err);
    }
  );
}

Create a function for checking the event on the specific date.

checkEvent(day) {
  var hasEvent = false;
  var thisDate1 = this.date.getFullYear()+"-"+(this.date.getMonth()+1)+"-"+day+" 00:00:00";
  var thisDate2 = this.date.getFullYear()+"-"+(this.date.getMonth()+1)+"-"+day+" 23:59:59";
  this.eventList.forEach(event => {
    if(((event.startDate >= thisDate1) && (event.startDate <= thisDate2)) || ((event.endDate >= thisDate1) && (event.endDate <= thisDate2))) {
      hasEvent = true;
    }
  });
  return hasEvent;
}

Create a function for showing the selected date events.

selectDate(day) {
  this.isSelected = false;
  this.selectedEvent = new Array();
  var thisDate1 = this.date.getFullYear()+"-"+(this.date.getMonth()+1)+"-"+day+" 00:00:00";
  var thisDate2 = this.date.getFullYear()+"-"+(this.date.getMonth()+1)+"-"+day+" 23:59:59";
  this.eventList.forEach(event => {
    if(((event.startDate >= thisDate1) && (event.startDate <= thisDate2)) || ((event.endDate >= thisDate1) && (event.endDate <= thisDate2))) {
      this.isSelected = true;
      this.selectedEvent.push(event);
    }
  });
}

Last, create a function for delete an event.

deleteEvent(evt) {
  // console.log(new Date(evt.startDate.replace(/\s/, 'T')));
  // console.log(new Date(evt.endDate.replace(/\s/, 'T')));
  let alert = this.alertCtrl.create({
    title: 'Confirm Delete',
    message: 'Are you sure want to delete this event?',
    buttons: [
      {
        text: 'Cancel',
        role: 'cancel',
        handler: () => {
          console.log('Cancel clicked');
        }
      },
      {
        text: 'Ok',
        handler: () => {
          this.calendar.deleteEvent(evt.title, evt.location, evt.notes, new Date(evt.startDate.replace(/\s/, 'T')), new Date(evt.endDate.replace(/\s/, 'T'))).then(
            (msg) => {
              console.log(msg);
              this.loadEventThisMonth();
              this.selectDate(new Date(evt.startDate.replace(/\s/, 'T')).getDate());
            },
            (err) => {
              console.log(err);
            }
          )
        }
      }
    ]
  });
  alert.present();
}

Now, open and edit again `src/pages/home/home.html` then replace all tags inside `<ion-content>` with this.

<ion-content padding>
  <div class="calendar-header">
    <ion-row class="calendar-month">
      <ion-col col-2 (click)="goToLastMonth()"><ion-icon name="arrow-back"></ion-icon></ion-col>
      <ion-col col-8>{{currentMonth}} {{currentYear}}</ion-col>
      <ion-col col-2 (click)="goToNextMonth()"><ion-icon name="arrow-forward"></ion-icon></ion-col>
    </ion-row>
  </div>
  <div class="calendar-body">
    <ion-grid>
      <ion-row class="calendar-weekday">
        <ion-col>Su</ion-col>
        <ion-col>Mo</ion-col>
        <ion-col>Tu</ion-col>
        <ion-col>We</ion-col>
        <ion-col>Th</ion-col>
        <ion-col>Fr</ion-col>
        <ion-col>Sa</ion-col>
      </ion-row>
      <ion-row class="calendar-date">
        <ion-col col-1 *ngFor="let lastDay of daysInLastMonth" class="last-month" (click)="goToLastMonth()">{{lastDay}}</ion-col>
        <ion-col col-1 *ngFor="let day of daysInThisMonth" (click)="selectDate(day)">
          <span class="currentDate" *ngIf="currentDate === day; else otherDate">{{day}}</span>
          <ng-template #otherDate class="otherDate">
            {{day}}<br>
            <div class="event-bullet" *ngIf="checkEvent(day)"></div>
          </ng-template>
        </ion-col>
        <ion-col col-1 *ngFor="let nextDay of daysInNextMonth" class="next-month" (click)="goToNextMonth()">{{nextDay}}</ion-col>
      </ion-row>
    </ion-grid>
  </div>
  <div class="selected-event" *ngIf="isSelected">
    <ion-list>
      <ion-item *ngFor="let se of selectedEvent">
        <ion-buttons end>
          <button ion-button clear icon-only (click)="deleteEvent(se)">
            <ion-icon name="close"></ion-icon>
          </button>
        </ion-buttons>
        <h2>{{se.title}}</h2>
        <h3>{{se.message}}</h3>
        <p>Start Date: {{se.startDate}}<br>
        Start Date: {{se.endDate}}</p>
      </ion-item>
    </ion-list>
  </div>
</ion-content>


Test and Run the Full Calendar and Event Apps

This Ionic Cordova Calendar plugin need to run on the device or simulator. For that, remove and add again the iOS and Android platform by typing this command.

ionic cordova platform rm android
ionic cordova platform add android
ionic cordova platform rm ios
ionic cordova platform add ios

Now, you can run on the devices or simulator by typing this command.

ionic cordova run android

or

ionic cordova run ios

Here they are.

Build Ionic 3 Angular 5 Calendar UI with Event Integration - Final Calendar UI and Event

That's it, this example of Ionic 3 Cordova Calendar event not completed because the feature of the plugin does not cover all functionality on Android and few on iOS. We know there's a lot of lacks because this is just an example of how to create your own Calendar UI instead of using an existing Calendar UI library. You can find the full source code on our GitHub.

We know that building beautifully designed Ionic apps from scratch can be frustrating and very time-consuming. Check Ionic 4 - Full Starter App and save development and design time. Android, iOS, and PWA, 100+ Screens and Components, the most complete and advance Ionic Template.

That just the basic. If you need more deep learning about Ionic, Angular, and Typescript, you can take the following cheap course:

Thanks!