AngularJs Calendar | Directive for the Arshaw JQuery fullcalendar

While working on our latest project a need for a calendar implementation was needed. Since rolling a custom calendar would be very time consuming other options were taken for the immediate solution. Searching the web for calendar implementations will return many different open source calendars. Most are inadequate for current web standards. The best implantation that we came across was Arshaws’ Fullcalendar jQuery implementation. We decided to write an angular directive wrapping this calendar to accentuate its features in an AngularJs environment.

The Angular UI framework is the most well tested open source companion suite for Angular JS on the market and is trusted by many developers that are harnessing the power of Angular in their apps. The approach taken to create directives is focused on utilizing the uiConfig object, which is just an empty json object that is filled with the users options at compile time. These options are fed into the directive to render dom elements accordingly. This is the approach that was taken to wrap the fullcalendar.

The bones of the directive are modeled after the already in place angular-ui directives. This made the process simpler and more efficient. First the ui-config is inserted into the directive, to give the user the ability to enter native fullcalendar options.

angular.module('ui.directives').directive('uiCalendar',['ui.config', '$parse', function (uiConfig,$parse) {
    uiConfig.uiCalendar = uiConfig.uiCalendar || {};

The ng-model tag is required for the calendar the render correctly. The idea to use ng-model instead of events was proposed by ProLoser. The original creator of the Angular-UI repository. The logic being that most people are familiar with the ng-model syntax and would understand it more coming from a noob experience level. The ultimate goal of ng-model in this specific case is to take in either an array of events or and events object that contains information about a data source. These event items are documented splendidly on Arshaw's website.

    return {
        require: 'ngModel',
        restrict: 'A',
        scope: {
          events: "=ngModel"
        },

There are multiple points of interest in the link function that will be explained. The first is how the options and expressions are configured and passed into the fullcalendar method. The default options are related to the navigation for the calendar. These are used to page through different views of the calendar. They were set to show the month, week, and day view. The expression variable is used to pull the attributes out of the ui.config element to allow for more options to be entered from the directive's html interface. There can be as many different options entered into the calendar as needed. This opens up a wide variety of implementations that are available.

The only native method that was wrapped for the calendar was eventMouseOver. This was because the other methods, such as event drag and drop have many different implementations that should be left up to the end user for their desired functionality. However true this may be the fact has recently come up that the event methods should be tied to the directive at least to show the date or time changing by dragging and dropping the events. This means that in the near future the methods will be added to the calendar and wired up to the scope.

</pre>
link: function(scope, elm, $attrs) {
 var ngModel = $parse($attrs.ngModel);
 //update method that is called on load and whenever the events array is changed.
 function update() {
 //Default View Options
 var expression,
 options = {
 header: {
 left: 'prev,next today',
 center: 'title',
 right: 'month,agendaWeek,agendaDay'
 },
 // add event name to title attribute on mouseover. Would be nice if this was an angular tooltip.
 eventMouseover: function(event, jsEvent, view) {
 if (view.name !== 'agendaDay') {
 $(jsEvent.target).attr('title', event.title);
 }
 },

//extend the options to suite the custom directive.
angular.extend(options, uiConfig.uiCalendar, expression);

This was the most monumental part of the calendar implementation for me. Once I had the ability to add in live events from the scope and insert them directly into the calendar I felt a sense of great accomplishment. This meant that the sky was the limit and we were just taking off.

</pre>
// Calling the events from the scope through the ng-model binding attribute.
 events: scope.events
 };

Everything that was explained before is all encompassed in the directive's update method. The update method is called on the initial load and whenever the length of the scope.events array changes. This is because it is much more efficient to watch just the length of the array, rather than the entire array itself. This watch method is credited to Andy Joslin. There was a request while the calendar was on the PR list for Angular-UI, that the events should update automatically if the scope changes. Since this is part of the beauty of AngularJS it was a must that this worked.

 //call fullCalendar from an empty html tag, to keep angular happy.
 elm.html('').fullCalendar(options);
 }
 //on load update call.
 update();
 //watching the length of the array to create a more effifient update process.
 scope.$watch( 'events.length', function( newVal, oldVal )
 {
 //update the calendar on every change to the length of the events array
 update();
 }, true );
 }
 };
 }]);
 

ui-calendar has a few dependencies, which must be included in the app to be able to work properly. Jquery is always required, as well as the fullcalendar.min.js file. The current implementation that we are showing on this post is a version that pulls in a live google feed to display the events. To do this the gcal.js file is required. If drag and drop is required, then the jquery-ui file is required.

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.js"></script><script type="text/javascript" src="https://raw.github.com/arshaw/fullcalendar/master/lib/jquery-ui-1.8.23.custom.min.js"></script>
<script type="text/javascript" src="http://www.dillingermediaonline.com/wp-content/themes/enterprise/js/fullcalendar.js"></script><script type="text/javascript" src="http://arshaw.com/js/fullcalendar-1.5.3/fullcalendar/gcal.js"></script>

The markup for the calendar is very simple now thanks to Angular.

</pre>
While working on our latest project a need for a calendar implantation was needed. Since rolling a custom calendar would be very time consuming other options were taken for the immediate solution. Searching the web for calendar implementations will return many different open source calendars. Most are inadequate for current web standards. The best implantation that we came across was <a title="Fullcalendar" href="http://arshaw.com/fullcalendar/" target="_blank">Arshaws' Fullcalendar</a> jQuery implementation. We decided to write an angular directive wrapping this calendar to accentuate its features in an AngularJs environment.

The <a href="http://angular-ui.github.com/" target="_blank">Angular UI</a> framework is the most well tested open source companion suite for Angular JS on the market and is trusted by many developers that are harnessing the power of Angular in their apps. The approach taken to create directives is focused on utilizing the uiConfig object, which is just an empty json object that is filled with the users options at compile time. These options are fed into the directive to render dom elements accordingly. This is the approach that was taken to wrap the fullcalendar.

The bones of the directive are modeled after the already in place angular-ui directives. This made the process simpler and more efficient. First the ui-config is inserted into the directive, to give the user the ability to enter native fullcalendar options.

1
angular.module('ui.directives').directive('uiCalendar',['ui.config', '$parse', function (uiConfig,$parse) {
    uiConfig.uiCalendar = uiConfig.uiCalendar || {};

The ng-model tag is required for the calendar the render correctly. The idea to use ng-model instead of events was proposed by ProLoser. The original creater of the Angular-UI repository. The logic being that most people are familiar with the ng-model syntax and would understand it more coming from a noob experience level. The ultimate goal of ng-model in this specific case is to take in either an array of events or and events object that contains information about a data source. These event items are documented splendidly on Arshaw's website.

    return {
        require: 'ngModel',
        restrict: 'A',
        scope: {
          events: &quot;=ngModel&quot;
        },

There are multiple points of interest in the link function that will be explained. The first is how the options and expressions are configured and passed into the fullcalendar method. The default options are related to the navigation for the calendar. These are used to page through different views of the calendar. They were set to show the month, week, and day view. The expression variable is used to pull the attributes out of the ui.config element to allow for more options to be entered from the directive's html interface. There can be as many different options entered into the calendar as needed. This opens up a wide variety of implementations that are available.

The only native method that was wrapped for the calendar was eventMouseOver. This was because the other methods, such as event drag and drop have many different implementations that should be left up to the end user for their desired functionality. However true this may be the fact has recently come up that the event methods should be tied to the directive at least to show the date or time changing by dragging and dropping the events. This means that in the near future the methods will be added to the calendar and wired up to the scope.

</pre>
link: function(scope, elm, $attrs) {
 var ngModel = $parse($attrs.ngModel);
 //update method that is called on load and whenever the events array is changed.
 function update() {
 //Default View Options
 var expression,
 options = {
 header: {
 left: 'prev,next today',
 center: 'title',
 right: 'month,agendaWeek,agendaDay'
 },
 // add event name to title attribute on mouseover. Would be nice if this was an angular tooltip.
 eventMouseover: function(event, jsEvent, view) {
 if (view.name !== 'agendaDay') {
 $(jsEvent.target).attr('title', event.title);
 }
 },

//extend the options to suite the custom directive.
angular.extend(options, uiConfig.uiCalendar, expression);

This was the most monumental part of the calendar implementation for me. Once I had the ability to add in live events from the scope and insert them directly into the calendar I felt a sense of great accomplishment. This meant that the sky was the limit and we were just taking off.

</pre>
// Calling the events from the scope through the ng-model binding attribute.
 events: scope.events
 };

Everything that was explained before is all encumbused in the directive's update method. The update method is called on the initial load and whenever the length of the scope.events array changes. This is because it is much more efficient to watch just the length of the array, rather than the entire array itself. This watch method is credited to Andy Joslin. There was a request while the calendar was on the PR list for Angular-UI, that the events should update automatically if the scope changes. Since this is part of the beauty of AngularJS it was a must that this worked.

 //call fullCalendar from an empty html tag, to keep angular happy.
 elm.html('').fullCalendar(options);
 }
 //on load update call.
 update();
 //watching the length of the array to create a more effifient update process.
 scope.$watch( 'events.length', function( newVal, oldVal )
 {
 //update the calendar on every change to the length of the events array
 update();
 }, true );
 }
 };
 }]);
 

ui-calendar has a few dependencies, which must be included in the app to be able to work properly. Jquery is always required, as well as the fullcalendar.min.js file. The current implementation that we are showing on this post is a version that pulls in a live google feed to display the events. To do this the gcal.js file is required. If drag and drop is required, then the jquery-ui file is required.

<script src="http://code.jquery.com/jquery-1.7.1.js"></script>
<script src="https://raw.github.com/arshaw/fullcalendar/master/lib/jquery-ui-1.8.23.custom.min.js"></script>
<script src="http://www.dillingermediaonline.com/wp-content/themes/enterprise/js/fullcalendar.js"></script>
<script src="http://arshaw.com/js/fullcalendar-1.5.3/fullcalendar/gcal.js"></script>

The markup for the calendar is very simple now thanks to Angular.

<div ng-controller="MainCtrl">
  <div ui-calendar="{height: 800,editable: true}" ng-model='eventSource'></div>
</div>

{{alertMessage}}

The full code base on git hub is located here ui-calendar

About joshkurz

Kennesaw State Graduate, Josh Kurz has a computer science degree and has been working with Dillinger Media as the Chief Information Officer. Recent work includes Pro Source Inc, RYECO, Kayal Dermatology & Med Spa. Also, owner of 321 Open Sesame, an Atlanta Locksmith.

Follow me on Google+

Speak Your Mind

*