Making a Calendar with Ionic2

03 February 2017 on Ionic2. 9 minutes

One of the most usefull piecies of functionality for any application is to schedule events. All sorts of apps need to schedule things or display schedules such as an event planning appliation, an enterprise coordination app, or maybe even a app for shift work.

Personally, I have been developing an app that allows users to schedule workouts for themselves or others. It will allow trainiers to make programs that they can then give to their athletes, or athletes make their own schedule of workouts.

This seems like a pretty simple set of requirements, so I was surprised when their was no Ionic supported plugin for this. Looking through their packages, there is a native Date Picker, but all this does is allow you to select a date (its also a bit outdated, in the github they reference Cordova v4). But the guys over at Ionic did something smart right off the bat, and everyone here also made a good decision when they decided to go with webviews, because now we can take advantage of any plugin or open source project from the angular2 community.

Angular Calendar

Enter Angular Calendar. I will show you how to incorporate this into your ionic project and modify it for a better mobile experience.

First we need to install and configure the project which is dead simple. Following the instructions from the github library,

npm install --save angular-calendar

Then we need to include the css file into our build. Normally in an angular2 project built with the cli we could just include this in our imports, but Ionic 2 uses Sass so its a bit different. I found the easiest way to incorporate it is to pull it down into your assests file and then include it in your index.html.

// Move node_modules/angular-calendar/dist/css/angular-calendar.css to src/assets


// index.html
  <link rel="stylesheet" href="assets/icons/flaticon.css">
  <link rel="stylesheet" href="assets/angular-calendar.css">
  <link rel="manifest" href="assets/manifest.json">

Ok so now when we build the css file will be available. Next we need to incorporate the module into our app.module.ts . From the documentation,

import { NgModule } from '@angular/core';
import { CalendarModule } from 'angular-calendar';

@NgModule({
  imports: [
    IonicModule.forRoot(MyApp),
    CalendarModule.forRoot()
  ]
})
export class MyModule {}

Now we can utilize the components that are provided

<mwl-calendar-month-view></mwlcalendar-month-view>
<mwl-calendar-week-view></mwlcalendar-week-view>
<mwl-calendar-day-view></mwlcalendar-day-view>

For the sake of brevity, i will just go over the month view calendar, and how to modify it. You should be able to take the same concepts and apply it to the week view and day view.

Ok, so now we have our custom calendar components, lets see what they look like.

// calendar.comp.html
<div class="calendar-comp">
    <mwl-calendar-month-view [viewDate]="today">
    </mwl-calendar-month-view>
</div>
// calendar.comp.ts
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { CalendarEvent } from 'angular-calendar';

@Component({
  selector: 'calendar',
  templateUrl: 'calendar.comp.html'
})
export class CalendarComp implements OnInit {
    public date: Date = new Date(Date.now());
    //...
}

And we get something like this!

Editing CSS for mobile

Pretty awesome that without much work at all we are able to get this kind of functionality. But right off the bat we can see that this isn’t optimized for mobile. The dates are very long, and the whole months calendar doesn’t even fit on the screen. lets optimize this for mobile a bit so that we can see the whole month on the screen, and do a few other things.

First we need to override the css that is making the day cells so large.

// calendar.comp.scss
.calendar-comp {
	.columnHeader {
		text-align: center;
		font-weight: bold;
	}
	.cal-today {
		.cal-day-number {
			font-size: 1.5em !important;
		}
	}
	.cal-day-cell {
		min-height: 60px;
	}
	.cal-cell-top {
		min-height: 30px;
	}
	.cal-day-number {
		font-size: 1em;
		margin-top: 10px;
		margin-bottom: 5px;
		margin-right: 5px;
	}
	.cal-day-badge {
		display: none;
	}
}

This will make the cells smaller, and optimize the badges and other special items so that will not make the cells particularly larger. Now we have a calendar that looks like this!

That looks so much better than what we originally had.

Custom Headers

A really great feature that this calendar allows is the ability to add a custom header template. If you are unsure of what a template is, check out the angular documentation, but basically we can insert it in the html that we already have to make it more mobile friendly.

In our custom header, we want to shrink the days of the week to abreviations so they fit better on the screen. To do this we add a template to our html, and then link it to the calendar

// calendar.comp.html
<div class="calendar-comp">
	<template #headerTemp>
		<div class="cal-cell-row">
			<div class="cal-cell cal-past columnHeader" *ngFor="let label of days_label">
				 {{label}} 
			</div>
		</div>
	</template>
	<mwl-calendar-month-view [viewDate]="date" [headerTemplate]="headerTemp">
	</mwl-calendar-month-view>
</div>
// calendar.comp.ts
  days_label: Array<string> = [
    'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'
  ];

Great. Now we have the ability to add a custom header to our calendar to display what ever information we want above.

Events

Ok so we have a good looking calendar, but a calendar is useless unless it has events in it. The documentation is a bit limited on this in the angular-calendar repo, so I will try my best to describe how to add events to the calendar and what they need to look like.

First lets show an example and then we can dive into the code a bit more.

// calendar.comp.ts
import { CalendarEvent } from 'angular-calendar';

...
  public colors: any = {
    red: {
      primary: '#ad2121',
      secondary: '#FAE3E3'
    },
  }
    public event: CalendarEvent = {
        start: this.date,
        title: 'Event!',
        color: this.colors.red
    }

Ok so we should talk about this “CalendarEvent” object. This was actually something that took some time to understand because it is based of a calendar-utils project that the owner of the repo created. The interface is described below.

export interface CalendarEvent {
  start: Date;
  end?: Date;
  title: string;
  color: EventColor;
  actions?: EventAction[];
  allDay?: boolean;
  cssClass?: string;
  resizable?: {
    beforeStart?: boolean;
    afterEnd?: boolean;
  };
  draggable?: boolean;
}


export interface EventColor {
  primary: string;
  secondary: string;
}

export interface EventAction {
  label: string;
  cssClass?: string;
  onClick({event}: {event: CalendarEvent}): any;
}

Now we have all the information we need to create a simple event and add it to the calendar.

// calendar.comp.ts
  public colors: any = {
    red: {
      primary: '#ad2121',
      secondary: '#FAE3E3'
    },
    blue: {
      primary: '#1e90ff',
      secondary: '#D1E8FF'
    },
    yellow: {
      primary: '#e3bc08',
      secondary: '#FDF1BA'
    }
  };
  public event: CalendarEvent = {
    start: this.date,
    title: 'Event!',
    color: this.colors.red
  }
  public calEvents: CalendarEvent[] = [this.event, this.event];

// calendar.comp.html
	<mwl-calendar-month-view 
    [viewDate]="date"
    [events]="calEvents"
    [activeDayIsOpen]="true">
	</mwl-calendar-month-view>

Now we have our completed calendar, that should look something like this!


Next

Push Notification with Ionic 3

One of the things that makes using instagram and pinterest so rewarding is when someone likes your post / photo. That instant gratificaiton when you get a little notification on your device that your friend liked the picture you took keeps you going back for more.