Skip to contentSkip to author details

Jeff Tyler

Jeff is a C# developer who has been developing software since 2007. In his free time, he enjoys playing around with new technologies or being out doors hunting, fishing or just hanging out.

Alabama, USA (map)

2 posts

Creating an Aurelia Bootstrap Calendar Of Events - Part 2 Create a custom element

Written by Jeff Tyler

This is part two of a multi-part tutorial on how to build a bootstrap calendar with Aurelia
Aurelia Calendar Part 1

Aurelia has a built in custom element modeled after web components. This will allow us to create a calendar widget that is isolated and reusable.

First we are going to create a folder called elements
Inside of the folder we will create another folder called calendar and a file called index.ts.
Inside of the calendar folder we will create two files
calendar.html and calendar.ts

We will start with the calendar.ts file. This file is the backing class for the custom element.

we'll break down the pieces and explain what it all is doing.

import { customElement, bindable, inject } from "aurelia-framework";  
import * as moment from 'moment';  
import * as $ from 'jQuery'  
@customElement("Calendar")
@inject(Element)
export class Calendar {

}

import tells it what extra classes we are going to need. If it's typescript then we can just name the class. Most things related to Aurelia is found in the aurelia-framework namespace. We are going to be using the customElement, bindable, and inject classes from aurelia-framework.

IF you are calling a pure JavaScript library then you import it by calling import * as (alias) from where you are getting it. We will be using the Javascript libraries from moment.js and jQuery.

@customElement('calendar') let's Aurelia know that this is going to be a customElement and that when we create an calendar element that we mean this.

@inject(Element) @inject is the Aurelia way of doing dependency injection. Anything in there will be automatically injected into the constructor. Element tells Aurelia to inject the actual Dom element into our constructor.

import { customElement, bindable, inject } from "aurelia-framework";  
import * as moment from 'moment';  
import * as $ from 'jQuery'  
@customElement("Calendar")
@inject(Element)
export class Calendar {  
    private today: moment.Moment;

    @bindable
    currentDate: Date;

    private element: Element
    constructor(element: Element) {
        this.today = moment();
        this.currentDate = this.today.toDate();
        this.element = element;
    }
}

today will hold today's date, so that we could style it differently if we so choose. @bindable tells aurelia to expose the property as an attribute and to allow them to bind to it. currentDate is the date that we will use for creating the calendar. It's basically a placeholder for the month and year.

element is the property to hold the Dom element.
constructor(element:Element) is a type script constructor and gives Aurelia a place to inject the Dom element.
inside the constructor we set today to moment() which creates a moment.Moment object for today's date.
It defaults currentDate to today by getting the date from the moment version. It will be overridden if someone binds the current-date attribute.

Here comes all of the code.

import { customElement, bindable, inject } from "aurelia-framework";  
import * as moment from 'moment';  
import * as $ from 'jQuery'  
@customElement("Calendar")
@inject(Element)
export class Calendar {  
    private today: moment.Moment;

    @bindable()
    currentDate: Date;

    element: Element
    constructor(element: Element) {
        this.today = moment();
        this.currentDate = this.today.toDate();
        this.element = element;
    }

    private getDisplayDates(): Array> {
        let dates = new Array>();
        let beginning = moment(this.currentDate).startOf('month').startOf('week');
        let currentMonth = this.currentDate.getMonth();
        for (let r = 0; r < 6; r++) {
            let week = new Array();
            for (let i = 0; i < 7; i++) {
                let date = {
                    dayOfWeek: beginning.format('dddd'),
                    date: beginning.date(),
                    darken: beginning.month() != currentMonth,
                    events: []
                }
//                if ((i * r) % 4 == 0) {
//                    date.events.push({ name: i.toString() //+ '-' + r.toString() + 'event', amount: i * r + 10 })
//                }
                week.push(date);
                beginning.add(1, 'days');
            }
            dates.push(week);
        }
        return dates
    }

    attached() {
        let that = this;
        var test = $(".calendarDay", $(this.element)).on('click', function (event) {
            let clickEvent = new CustomEvent('day-click', {
                detail: { value: event.target },
                bubbles: true
            })
            that.element.dispatchEvent(clickEvent);
        });
    }
}

Here we added two new methods. getDisplayDates and attached.

getDisplayDates creates an array of arrays of objects used to render the calendar.

beginning turns takes current date and gets the Sunday of the week that the 1st of the month falls on. So for instance for the month of August 2017 it would start at July 30 2017 in the US. If your are localized in a country that has a different start of the week then it will start there instead.

it loops through 6 weeks of 7 days creating an object that holds the date(30,31,1...), the day of week (Monday, Tuesday...) and darken which is a flag for whether the date is within the month held by currentDate.
It also holds an events array used to hold the events to display for that day. Eventually this would be populated by an ajax call for the data.

The commented out section basically creates some dummy data to see what it might look like with events. Uncomment it if you want to get an idea.

attached()

Attached is part of the Aurelia life cycle. It is the last chance to act upon an element. Here we are creating a custom event to be bound to when the a particular day is clicked.
let that = this allows us to access the typescript class from withing the jQuery event.

We add a jQuery event onto all of the calendarDays within this element. Then we create a customEvent and dispatch it so that any listeners can act upon it. It passes the Dom element that was clicked to the event.

Creating an Aurelia Bootstrap Calendar Of Events - Part 1 Getting Started and Overriding Bootstrap

Written by Jeff Tyler

I needed a calendar as a centerpiece for an application that I am working on. After looking through the internet for something that I liked and not finding it. I decided to do what all sane programmers do. Build my own. So let's get started. YeeHaw!!
Here are the requirements that I have set for myself, and how I plan to fix it.

  • Must be responsive: for this I am going to use bootstrap. 7 days on a week for a full screen and 2 for small.
  • Two Headers: header 1: Monday 31. Header 2: Useful Information
  • Must be able to display multiple events on a given day.

Few events truly span multiple days. There is usually a beginning and end of the first day and a beginning and end of the second day. So this is how i intend to treat it.

Getting Started.

I like being explicit so I am going to list my assumptions and what I have done to meet them. If you have the same set up as me, then you can follow exactly, if yours is different then do your own thing where we deviate.

Assumptions
  1. You have an Aurelia Application set up and running.
  2. you have bootstrap 3 less files
  3. You have a LESS compiler set up
  4. You have moment.js
  5. You are using TypeScript

My set up
1. .netcore C# aurelia app by running dotnet new aurelia
2. dotnet automatically includes bootstrap through npm when you create a new aurelia app.
3. less-loader through webpack
4. npm install moment -save

Steps involved
  1. Change bootstrap from a grid of 12 to a grid of 14.
  2. Create an custom element for aurelia.
  3. Create grids and rows to hold the dates
  4. Populate the grids with dates
  5. Remove padding for rows inside of the calendar.
1. Change bootstrap from a grid of 12 to a grid of 14.

There are seven days in a week. So it would make since for seven columns to exist in a row. A seven column bootstrap doesn't give much flexibility for the rest of the application to use for layouts. If we treat the rows and columns inside of the calendar differently then you have a lot of repeated CSS to handle the special case. Twelve columns don't work well when you need seven columns. However with fourteen columns the rest of the application is a little more flexible and you have one grid system throughout everything so there isn't a special case. So we are going to increase the number of columns for bootstrap using LESS.

So first we are going to create a file called myLess.less

open the file and add these three lines of code.

@import '~bootstrap/less/variables.less';  
@grid-columns: 14;
@import '~bootstrap/less/bootstrap.less';

Your path may be different depending on what you use to compile the less files. The tilda in this case tells webpack to look in node_modules.

@import is a less command that allows us to reference other less files.

First we bring in the variables file for bootstrap. This file holds all of the settings bootstrap uses to set it's self up. It's worth looking at the file and seeing what all is there that you could change.

For our purposes we only need to change the @grid-columns variable from the default of 12 to 14

next we import the main bootstrap.less file. This file is a wrapper file around all of the bootstrap components and will give you everything that you would have gotten if you just used the bootstrap.css file directly except now it uses a 14 column grid instead.

Continue on with Aurelia Calendar Part 2