Javascript

Fancy calendars for your web application with FullCalendar


While working on a project, I had the need of adding some calendars to display information from events already saved on a RoR application. Fortunately, I had done something similar for a project during my last semester of college using a fantastic Javascript library called FullCalendar created by Adam Shaw.

In this blogpost, I'll guide you through the process of integrating the calendar with an existent Ruby on Rails application by using one of the new features that comes included with Rails 4 by default: jbuilder

Hands on

We are going to create a simple Rails 4 app to demonstrate the integration but, if you already have an application that needs a calendar, this example will also help you. That is because the 'magic' that glues together the calendar with our application lies on what jbuilder does: creating a JSON response

Let's create an scaffold for a model called 'Event' with some attributes to display in our calendar:

rails generate scaffold Event title:string description:text start_time:datetime end_time:datetime

And don't forget to run migrations and run the server:

rake db:migrate
rails server

Now that we are ready, we can navigate to localhost:3000/events and see our brand new event list.

image alt

We can see the JSON representation of our events by going to localhost:3000/events.json

image alt

Setting up the calendar

We can download the necessary assets from the FullCalendar webpage or using the FullCalendar-rails gem. In case that you, as me, prefer to use it as a gem, we only need to add it our Gemfile

gem 'fullcalendar-rails'

And then run

bundle install

At this point, the files are already in the assets pipeline's path and the final step is to require them in our application.* files:

In application.css.scss we'll add

*= require fullcalendar

And in our application.js

//= require fullcalendar

In order to feed our calendar, we need to create some events either from the web interface created by the scaffold or using the Rails console: I will leave this part up to you.

We need to create a div in our view and initialize the calendar using jQuery:

$('#calendar').fullCalendar();

And we have our fullCalendar up and running:

image alt

Note: I made it smaller using CSS: by default, the calendar takes all the width available

Let's move to the backend

Now that our calendar looks awesome, we need to work on how the events are going to be displayed and, yes, it is time to move on to Rails.

There are many ways to load our events in the calendar but the most interesting and useful for this example is to provide the calendar with a URL where it can get the events as a JSON array. This array will look similar to this:

    [
        {
            title  : 'event1',
            start  : '2010-01-01'
        },
        {
            title  : 'event2',
            start  : '2010-01-05',
            end    : '2010-01-07'
        },
        {
            title  : 'event3',
            start  : '2010-01-09 12:30:00',
            allDay : false
        }
    ] 

We need to make sure to return our JSON according to this format, this is where jbuilder will help us.

The JSON way

The scaffold we used to generate the application has already provided us with a handy way of adding JSON support: we can take a look at app/views/events/index.json.builder file and see the default format it provides:

json.array!(@events) do |event|
  json.extract! event, :id, :title, :description, :start_time, :end_time
  json.url event_url(event, format: :json)
end

It just takes all the events and its attributes and creates an array. We can see the output by visiting localhost:3000/events.json

image alt

So close! It looks very similar to the format fullCalendar expects but we need to make a couple of changes to make it match:

json.array!(@events) do |event|
  json.extract! event, :id, :title, :description
  json.start event.start_time
  json.end event.end_time
  json.url event_url(event, format: :html)
end

We had to rename the start\time_ and end\time_ to start and end.

Additionally, we changed the format of the URL attribute from :json to :html. I'll explain this in the next step.

Our new output will look similar to this:

image alt

When frontend meets backend

Now that our backend provides us with a JSON response in the same format that fullCalendar needs, we need to go back where we initialized our fullCalendar and send the proper params:

$('#calendar').fullCalendar(
    events: '/events.json'
);

And we are done! now our calendar shows the events we have added:

image alt

Remember the change we did in the index.json.builder file about pointing our URL attribute to its HTML version instead of the JSON one? We'll, this change allows us to point to our '/events/{id}.html' route when we click on an event.

Wrapping up

It is worth to notice that you are not tied to using jbuilder for creating the JSON response: you can use ActiveModel::Serializer, Rabl or whatever that fits your application needs… or even better, you could use fullCalendar without RoR, another framework or even a different language might work. The key for the integration is to follow the JSON format that fullCalendar requires.

I really encourage you to read the documentation to know about all the customization that fullCalendar supports: it is a very flexible and powerful library and I bet you don't want to miss all the options it provides.

Finally, you can take a look at this example in this github repository specially created for this blogpost.

Thanks for reading!

Web dev
REST API Calls using SWIFT
Beginner
ReactJS: Loops in JSX
Javascript
AngularJS Providers under the hood
  • CPHollister

    This worked great for a recruiting app to create interviews. Thanks!

    • So glad you found this useful! Thanks for reading!

  • Arin

    Found this very useful, next feature that would be useful is recurring events.

  • I tried a lot of other calendar gems and solutions but this is, by far, my favorite! Thank you.

    • Hi, Wilfrid!

      Indeed, it is my favorite one too 🙂

      Regards!

  • Alex

    Hey Fer, tuviste algún tipo de problemas con el i18n o solo lo utilizaste en Inglés? Saludos.

    • Hola!

      Para este ejemplo y el proyecto donde lo he estado utilizando, sólo lo usé en inglés. No deberías tener problemas para i18n con las respuestas JSON.

      Saludos!

  • RailsNewb

    Thanks for the post!

    Where do you put the “json.array!(@events)… ” block? In the controller? The Event model?

    • Those changes are for the jbuilder file generated by the scaffold. If you are using something else to generate it, you don’t need it

  • RailsNewb

    Nevermind 😉 app/views/events/index.json.builder

  • RailsNewb

    Hmmm it doesn’t seem to matter what the contents of app/views/events/index.json.jbuilder is, or even whether the file exists. /events.json always returns every column in the Events table. Why is my index.json.jbuilder file being ignored by rails4?

  • Guest

    Can you make this calendar horizontal & add 3 cells to each number of a day?

    • Hi!

      Haven’t really played a lot with the default styles of the calendar.

      There are similar question on stackOverflow with the tag ‘fullCalendar’ that can be a good guidance to help you achieve what you want

      Regards!

  • Inbev77

    Can you make this calendar horizontal & add 2 cells to each number of a day to display the events?

  • Shawn Douglass

    Thanks, very helpful.

  • Alex

    im not sure where this goes –>

    (‘#calendar’).fullCalendar();

    • For this example, you can put it on your application.js.coffee file.

  • Root

    Extremley helpful, great article, the most clean and precise i’ve found for a calendar solution. Thank you!

  • Mayur Thole

    Can you please provide a complete code…link…?

  • Joe

    Thanks! I have tried to implement this on my own App based on finished projects and long (and annoying) code samples. You made me understand how and why this works.

  • Luke Wilcox

    This was very helpful, thanks!

  • Felix Leal

    Muy buenas tardes mi pana… tengo esta situacion despues de realizar la practica me quede trancado en un paso..

    cuando trato de incluir el archivo events.json en el fullcalendar me sucede esto:

    SyntaxError: missing ) after argument list events:75:44

    en donde la linea 75 es:
    $(‘#calendario_uno’).fullCalendar(events: ‘events.json’);

    y la columna 44 es: event(AQUI)s: ‘events.json’
    si me pudieras ayudar… feliz dia…

    • Felix Leal

      Disculpa ya lo arregle:

      $(‘#calendario_uno’).fullCalendar({
      events: ‘/events.json’
      });
      se le tenia que colocar {}.
      gracias.

      • Fernando Perales

        Hola! Lamento haber tardado tanto en responde. Qué bueno que pudiste encontrar pronto la solución. Saludos!

  • dheyfesson

    Hello Fernando,
    thanks for the excellent tutorial.
    follow the steps and managed to display the calendar.
    but how do I display the buttons “prev”, “next”, “month”, “week”, “day”?

    • Fernando Perales

      Hi! Thanks for reading! When you initialize the calendar, you can pass the left, center and right options that will determine what will be shown in the header. Take a look at the docs for the full list of valid options http://fullcalendar.io/docs/display/header/

  • ToyMechQM

    How exactly do I implement the print.css portion. When I add it to my requirements it overrides the main calendars css…. and How do I add the print button.

    • Fernando Perales

      Hi! Thanks for reading! When you say print.css, do you refer to this http://printstylesheet.com/? Haven’t implemented both together.

  • Samra

    Hi Fer. I checked the example code you provided. calendar is not displaying. I added new events too but still there is no calendar. help please.

    • random

      i had the same problem.. change the gem version to 2.0.2.0 and it works

      • Samra

        hey. it really worked. you proved to be a great help. thank you soooooooo much.

      • Fernando Perales

        Thanks to both of you! Haven’t catch up with the new releases of the gem, but it seems something is being done differently. I’ll take a look and update accordingly for further readers. Regards

  • Anonymous

    Hey Fer. I am getting “Uncaught TypeError: undefined is not a function” as an error. Have you seen this before?

    • Anonymous

      So this problem was only resulting when I was including the JS in the asset pipeline. If I remove it form the pipeline and include it directly onto the page it works just fine.

      • Fernando Perales

        So glad it didn’t take you too long to fix the error. It should work the same way by including it on the pipeline. Maybe the location or the name of the file is wrong.

  • great tut thanks for this 🙂 this worked for me but i need some more functionality like i want my project due_date to show in the calendar as well , i repeated the tutorial and added this line to the .js file (events: ‘events/json’ events: ‘projects/json’ ) is this the correct way to do this? or there is something better

    • Hi! Thanks for reading. Not sure if I got the whole picture, but you want to show not only a date for an event but also the due date for the same one, right?

      The jQuery plugin only supports one declaration of the ‘events’ attribute (the one who points to your JSON source) but it provides a ‘eventsSources’ which is the one you are looking for.

      Instead of

      events: ‘events/json’

      you have to change that line into something similar to this:

      eventSources: [
      ‘events/json’,
      ‘projects/json’,
      ]

      Take a look at the eventSources entry in the docs for further explanation

      http://fullcalendar.io/docs1/event_data/eventSources/

      Regards

      • thanks Fer Perales this is exactly what i was looking for 🙂

      • hey Fer

        is there anyway by which i can use dynamically generated url ? Like calender for

        events: “projects/#{params[:id]}/events.json”

        rather than hard coding it, right now i have hard coded it as

        events: ‘/’projects/2.json”

        regards

  • zuan

    hai Fer..
    I do love this tutorial..
    But im having a problem here:
    1st : failed to display created event in the calendar..
    2nd : the calendar did not appear if i click the button (link_to events_path) where i locate the calendar div inside event index file unless if i click url at the top of the browser then click enter, it will appear then.
    May u guide me sir 🙂
    Thanks

    • Hi, Zuan!

      Can you show me which errors have you encountered?

      Regards,

      • Zuan

        Hi fer..thanks for ur concern..
        I fix it by not using data-tubolink..
        The rest seems quite fine..
        Terima Kasih! 🙂

  • midas

    Wow! Almost exactly what I want to do. I am migrating from many years of PHP. This would make a wonderful introduction to RoR. Have you thought of adding user authentication? How about different colors for different user events?

    I’ll be studying this for a while to get my bearings and add the items I suggested. Thank you. This is a real boon to the RoR community (particularly noobs like me 😉

    -m

    • Andrew Cowle

      You can easily add different colors for events (based on either an event type or a creating user) by passing a hex code (e.g. #000000) from your event model into the json as backgroundColor.

      e.g. /events.json.builder

      json.array!(@events) do |event|
      json.extract! event, :id, :title
      json.backgroundColor event.setting_event_type.color
      json.borderColor event.setting_event_type.color
      json.start event.due_date
      json.allDay true
      json.url task_url(event)
      end

    • Hi, midas!

      For authentication, devise gem is usually the way to go. Depending what and how do you want to project your app or your API, is what you should do

      Regards,

  • Chaitanya Dvsk

    Hello, I tried following the same steps but the calendar does not

    show up on my rails app, is it because of any version difference. Please suggest!

    • Hi, Chaitanya!

      Yes, it may happen that the newest versions of either Rails or full calendar gem may not be totally backwards-compatible with the ones I used for the example

      Which versions are you using?

      Regards,

    • I’ve noticed that you need to add momentjs-rails gem and include moment before fullcalendar in application.js to make it work.

  • CapnMorgan71

    Thanks for the tutorial, it was awesome! Worked Well! 🙂

    One issue I ran into was index.json.builder had to be named index.json.jbuilder

    • Hi, CapnMorgan71!

      Glad you found this useful

      It may happen that the newest verions of jbuilder changed the format of the file. In this case, the file was generated when running the scaffold

      Regards

  • CapnMorgan71

    Great Tutorial. An Update that might be helpful for people is index.json.builder to index.json.jbuilder

    (sorry if repost but changed user name and my last comment disappeared

  • Samra

    Can you please provide some tutorial or suggest something to add reminders with events. user might be reminded via email or desktop notification. I have been working on it and so far could not find any solution.

  • José S. Barrientos

    I am trying to replicate this example with your code on Github but I am afraid I get the error ”

    ExecJS::RuntimeError in
    Events#index” before checking the back end part. Any ideas why is this happening?

    Update: I solved the error, I think I had something extra here and there.

    However I was not able to replicate this in the current gems versions. Can you please let me know if I need to update anything to have it working?

    • H, José! This blogpost was written more than a year ago and was using the latests version of the gems at that moment. Since I didn’t use an specific version in the Gemfile, is very probable that the latests versions nowadays are not backwards-compatible.

      Regards,

      • José S. Barrientos

        Thanks anyway! It is a great tutorial, in case you decide to make a little update I would like to know.

        • I’ll take a look at the latest changes in the gem and, if it is worth to make a new blogpost explaining new features, I’ll do it.

          Thanks for your comments!

  • Rafael Rezende Costa

    Thank !!