Skip to content

Creating a calendar app using Full Calendar, JavaScript, Bootstrap


Single page calendar app that meets given specs. Check out a demo. Or, play with the code!

This project stretched my JavaScript abilities. In fact, when I started this project, the project was beyond my comfort level. I had completed several algorithm challenges, used jQuery, and was familiar with JavaScript syntax. I couldn’t wrap my head around interacting with the DOM. My friends and family encouraged me to try my best. I studied to get my jQuery, Full Calendar, and JavaScript skills up to snuff. To complete this project, I tried the following:

Project Requirements and Implementation

I will walk you through the requirements of the project and discuss how I met (or… did not meet) each one.

Current iterationWalk through of previous iteration

The user interface should generally have two panes

I used my best Googles to come up with a solution. I’m thinking this idea originated somewhere in StackOverflow but I got lost in a sea of tabs. I wanted to use the same calendar object and show that calendar in the left pane and right pane. I didn’t want to have to do everything twice, so I added a calendar class to both the left and right panes. Then, I added an id of calendar1 to the left pane and an id of calendar2 to the right pane. In the calendar.js file, I declare these panes $cal1 and $cal2.

<div class="container-fluid row">
  <div id='calendar1' class='calendar col-md-8'></div>
  <div id='calendar2' class='calendar col-md-4'></div>

One pane should have a calendar with clickable days, the other should have time slots for a selected day

I used Full Calendar’s changeView method so the right pane would open to the agendaDay view.

$cal2.fullCalendar('changeView', 'agendaDay');

I also restricted the headers of $cal1 and $cal2. I wanted the left pane to only allow a month or week view. The right pane should only allow the day view.

/* header for $cal1 */
header: {
  left: 'prev,next today',
  center: 'title',
  right: 'month,agendaWeek'
/* header for $cal2 */
header: {
  right: 'prev,next today'

Then, I used Full Calendar’s dayClick and eventClick methods to attach an event to the days in the left view.

dayClick: function(date) {
eventClick: function(calEvent) {

The function cal2GoTo moves the calendar on the right to the day clicked.

var cal2GoTo = function(date) {
  $cal2.fullCalendar('gotoDate', date);

Chose time slots to be in any increment

When I started, I wanted no restrictions on appointment length. However, I had issues getting calendar 1 and calendar 2 to render properly after updating an appointment. I also had issues with repeating events and multi-day events. I hope to iron out these issues, but I needed to keep moving. So, I scaled back and decided to limit appointments to 30 minutes. I used a few Full Calendar methods to force the 30 minute appointments.

defaultTimedEventDuration: '00:30:00',
forceEventDuration: true,

I also set the options allDaySlot: false and editable: false.

Each time slot is linked to a prompt to create an appointment

Using Full Calendar’s select and eventClick methods, I added a click event to calendar 2 to begin the process of editing or creating events.

select: function(start, end) {
eventClick: function(calEvent, jsEvent, view) {

The new event function was simpler to implement than the edit event function. I added Bootstrap modals to get the appointment title from the user.

var newEvent = function(start) {
  $('#submit').on('click', function() {
  var title = $('input#title').val();
  if (title) {
    var eventData = {
        title: title,
        start: start
    $cal.fullCalendar('renderEvent', eventData, true);
  else {
    alert("Title can't be blank. Please try again.")

When I created the newEvent function, I didn’t include $(‘input#title’).val(“”); or $(‘#submit’).unbind();. But, after testing, I noticed events were propagating unexpectedly after the creation of new appointments. These lines fixed that problem.

The edit function was slightly more difficult. This project did not require persistence, so there was issues with the ids of newly created appointments. Occasionally, Full Calendar has ids with _fc ammended. Also, with newly created events, the id on calendar 1 was different than the id on calendar 2. So, I needed to consider this when rendering the event on calendar 1 and calendar 2.

var editEvent = function(calEvent) {
  $('#update').on('click', function() {
    var title = $('input#editTitle').val();
    var eventData;
    if (title) {
      calEvent.title = title
      $cal.fullCalendar('updateEvent', calEvent);
    } else {
    alert("Title can't be blank. Please try again.")
  $('#delete').on('click', function() {
    if (calEvent._id.includes("_fc")){
      $cal1.fullCalendar('removeEvents', [getCal1Id(calEvent._id)]);
      $cal2.fullCalendar('removeEvents', [calEvent._id]);
    } else {
      $cal.fullCalendar('removeEvents', [calEvent._id]);
var getCal1Id = function(cal2Id) {
  var num = cal2Id.replace('_fc', '') - 1;
  var id = "_fc" + num;
  return id;

Getting Distracted with Rails and Bootstrap DateTimePicker

Even though persistence wasn’t required, I decided I wanted to persist the data. I knew Rails would help me clean up my files, provide helpful gems, and allow for partials. After a few hours of work, I realized Rails was overkill. I decided to go back and wait on extra features. I created a Rails branch and rolled back commits.

I wanted to make the appointment times editable. I tried to use bootstrap-datepicker, bootstrap-datetimepicker, bootstrap-timepicker, and others. I was having trouble adding the date picker in the modal. I was also having issues grabbing the date and time from the modal and adding that to the calendar. So, a user cannot move an appointment but I hope to make this work sometime soon.

I look forward to adding persistence and improving usability.

Posted in Javascript, jquery. Tagged with , , .

0 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

You must be logged in to post a comment.