FullCalendar Example with Client-Side Event Updates

Hey everyone,

I’ve been mucking around with FullCalendar recently and decided to share one of the prototypes I’ve ended up with. It basically lets the user change the events without having to do a postback. A user simply has to click the event, type in the changes and hit update.

I’ve posted the code below, however there’s also a zip which is a little easier to manage. Note that you’ll probably want to clean it up a little if you plan to use it in production. The following libraries and plugins are also used:
jQuery
jQuery UI
jQuery FullCalendar
jQuery miniColors

What it Looks Like:

Full Calendar Example with Client Side Edits
Full Calendar Example with Client Side Edits

How to Use It:

It’s all pretty straight forward, but just in case any one runs into issues there are two parts to this example. First, you generate an event template. You can then drag and drop this template onto the calendar as many times as you want.

The second part allows you to edit existing events without posting back to the server. To do this, simply click an event and then make the necessary adjustments using the top panel on the right. Once you’re done, just press update event.

The example uses the standard title property, but also includes a few others: descriptions, price, available. You can change/remove these to suit your needs, just remember to pull them out of the JavaScript as well.

Zip:

Full Calendar Zip

Basic Example Page:


	

		
		
		
		
		
	
	

		
		
Background:

Border:

Text:





Description


One Hour
http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js http://js/jquery-ui-1.9.2.custom.min.js http://js/fullcalendar.js http://js/view_calendar.js http://js/jquery.miniColors.js

Basic JavaScript:

/* Wait for DOM to load etc */
$(document).ready(function(){

	//Initialisations
	initialise_calendar();
	initialise_color_pickers();
	initialise_buttons();
	initialise_event_generation();
	initialise_update_event();
});


/* Initialise buttons */
function initialise_buttons(){

	$('.btn').button();
}


/* Binds and initialises event generation functionality */
function initialise_event_generation(){

	//Bind event
	$('#btn_gen_event').bind('click', function(){

		//Retrieve template event
		var template_event = $('#external_event_template').clone();
		var background_color = $('#txt_background_color').val();
		var border_color = $('#txt_border_color').val();
		var text_color = $('#txt_text_color').val();
		var title = $('#txt_title').val();
		var description = $('#txt_description').val();
		var price = $('#txt_price').val(); 
		var available = $('#txt_available').val();

		//Edit id
		$(template_event).attr('id', get_uni_id());

		//Add template data attributes
		$(template_event).attr('data-background', background_color);
		$(template_event).attr('data-border', border_color);
		$(template_event).attr('data-text', text_color);
		$(template_event).attr('data-title', title);
		$(template_event).attr('data-description', description);
		$(template_event).attr('data-price', price);
		$(template_event).attr('data-available', available);

		//Style external event
		$(template_event).css('background-color', background_color);
		$(template_event).css('border-color', border_color);
		$(template_event).css('color', text_color);

		//Set text of external event
		$(template_event).text(title);

		//Append to external events container
		$('#external_events').append(template_event);

		//Initialise external event
		initialise_external_event('#' + $(template_event).attr('id'));

		//Show
		$(template_event).fadeIn(2000);
	});
}


/* Initialise external events */
function initialise_external_event(selector){

	//Initialise booking types
	$(selector).each(function(){

		//Make draggable
		$(this).draggable({
			revert: true,
			revertDuration: 0,
			zIndex: 999,
			cursorAt: {
				left: 10,
				top: 1
			}
		});

		//Create event object
		var event_object = {
			title: $.trim($(this).text())
		};

		//Store event in dom to be accessed later
		$(this).data('eventObject', event_object);
	});
}


/* Initialise color pickers */
function initialise_color_pickers(){

	//Initialise color pickers
	$('.color_picker').miniColors({
		'trigger': 'show',
		'opacity': 'none'
	});
}


/* Initialises calendar */
function initialise_calendar(){

	//Initialise calendar
	$('#calendar').fullCalendar({
		theme: true,
		firstDay: 1,
		header: {
			left: 'today prev,next',
			center: 'title',
			right: 'month,agendaWeek,agendaDay'
		},
		defaultView: 'agendaWeek',
		minTime: '6:00am',
		maxTime: '6:00pm',
		allDaySlot: false,
		columnFormat: {
			month: 'ddd',
			week: 'ddd dd/MM',
			day: 'dddd M/d'
		},
		eventSources: [
			{
				url: 'calendar_events.json',
				editable: false
			}
		],
		droppable: true,
		drop: function(date, all_day){
			external_event_dropped(date, all_day, this);
		},
		eventClick: function(cal_event, js_event, view){
			calendar_event_clicked(cal_event, js_event, view);
		},
		editable: true
	});	

	//Initialise external events
	initialise_external_event('.external-event');
}


/* Handle an external event that has been dropped on the calendar */
function external_event_dropped(date, all_day, external_event){

	//Create vars
	var event_object;
	var copied_event_object;
	var duration = 60;
	var cost;

	//Retrive dropped elemetns stored event object
	event_object = $(external_event).data('eventObject');

	//Copy so that multiple events don't reference same object
	copied_event_object = $.extend({}, event_object);
	
	//Assign reported start and end dates
	copied_event_object.start = date;
	copied_event_object.end = new Date(date.getTime() + duration * 60000);
	copied_event_object.allDay = all_day;

	//Assign colors etc
	copied_event_object.backgroundColor = $(external_event).data('background');
	copied_event_object.textColor = $(external_event).data('text');
	copied_event_object.borderColor = $(external_event).data('border');

	//Assign text, price, etc
	copied_event_object.id = get_uni_id();
	copied_event_object.title = $(external_event).data('title');
	copied_event_object.description = $(external_event).data('description');
	copied_event_object.price = $(external_event).data('price');
	copied_event_object.available = $(external_event).data('available');

	//Render event on calendar
	$('#calendar').fullCalendar('renderEvent', copied_event_object, true);
}


/* Initialise event clicks */
function calendar_event_clicked(cal_event, js_event, view){

	//Set generation values
	set_event_generation_values(cal_event.id, cal_event.backgroundColor, cal_event.borderColor, cal_event.textColor, cal_event.title, cal_event.description, cal_event.price, cal_event.available);
}


/* Set event generation values */
function set_event_generation_values(event_id, bg_color, border_color, text_color, title, description, price, available){

	//Set values
	$('#txt_background_color').miniColors('value', bg_color);
	$('#txt_border_color').miniColors('value', border_color);
	$('#txt_text_color').miniColors('value', text_color);
	$('#txt_title').val(title);
	$('#txt_description').val(description);
	$('#txt_price').val(price);
	$('#txt_available').val(available);
	$('#txt_current_event').val(event_id);
}


/* Generate unique id */
function get_uni_id(){

	//Generate unique id
	return new Date().getTime() + Math.floor(Math.random()) * 500;
}


/* Initialise update event button */
function initialise_update_event(){
	var test = $('#calendar').fullCalendar( 'clientEvents');
	//Bind event
	$('#btn_update_event').bind('click', function(){

		//Create vars
		var current_event_id = $('#txt_current_event').val();

		//Check if value found
		if(current_event_id){

			//Retrieve current event
			var current_event = $('#calendar').fullCalendar('clientEvents', current_event_id);

			//Check if found
			if(current_event && current_event.length == 1){

				//Retrieve current event from array
				current_event = current_event[0];

				//Set values
				current_event.backgroundColor = $('#txt_background_color').val();
				current_event.textColor = $('#txt_text_color').val();
				current_event.borderColor = $('#txt_border_color').val();
				current_event.title = $('#txt_title').val();
				current_event.description = $('#txt_description').val();
				current_event.price = $('#txt_price').val();
				current_event.available = $('#txt_available').val();

				//Update event
				$('#calendar').fullCalendar('updateEvent', current_event);
			}
		}
	});
}

Stylesheet

body{
	font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
	font-size: 12px;
}

#content_wrapper{
	width: 820px;
	margin-left: auto;
	margin-right: auto;
}

#calendar{
	width: 650px;
	float: left;
}

.btn{
	font-size: 85%
	margin-top: 10px;
}

#event_generation_wrapper{
	float: left;
	width: 120px;
	background-color: #DDD;
	margin-left: 20px;
	margin-top: 40px;
	border: 1px solid #4297D7;
	background-color: #FCFDFD;	
	-moz-border-radius: 3px;
	-webkit-border-radius: 3px;
	border-radius: 3px;
	padding: 10px 5px 10px 5px;
}

#event_generation_wrapper .left{
	float: left;
	width: 70px;
}

#event_generation_wrapper .right{
	float: left;
	max-width: 25px;
	margin-left: 10px;
}

#event_generation_wrapper input{
	width: 112px;
}

#event_generation_wrapper textarea{
	width: 110px;	
	height: 50px;
}

#event_generation_wrapper .miniColors-triggerWrap{	
	margin-bottom: 5px;
}

#event_generation_wrapper .text{
	padding-top: 1px;	
	margin-bottom: 5px;
	line-height: 10px;
}


#external_events{
	float: left;
	width: 130px;
	background-color: #DDD;
	margin-left: 20px;
	margin-top: 40px;
	border: 1px solid #4297D7;
	background-color: #FCFDFD;	
	-moz-border-radius: 3px;
	-webkit-border-radius: 3px;
	border-radius: 3px;
}

#external_events .external-event{
	width: 100px;
	margin: 5px;
	font-family: Verdana, Arial, sans-serif;
	border: 1px solid #36C;
	padding: 3px;
	text-align: center;
	background-color: #36C;
	color: white;
	cursor: pointer;
	-moz-border-radius: 3px;
	-webkit-border-radius: 3px;
	border-radius: 3px;
}

#calendar .ui-widget-header{
	font-weight: normal;
	padding: 3px 3px 3px 3px;
}

#calendar .fc-header-title{
	font-weight: normal;
}

#external_event_template{
	display: none;
}

Basic List of Events (JSON):

[
    "0",
    {
        "allDay": "",
        "title": "Test event",
        "id": "821",
        "start": "2012-11-23 14:00:00",
        "end": "2012-11-23 15:00:00"        
    },
    "1",
    {
        "allDay": "",
        "title": "Test event 2",
        "id": "822",        
        "start": "2012-11-23 9:00:00",
        "end": "2012-11-23 10:00:00"
    },
    "2",
    {
        "allDay": "",
        "title": "Test event 3",
        "id": "823",        
        "start": "2012-11-24 8:00:00",
        "end": "2012-11-24 6:00:00"
    },
    "3",
    {
        "allDay": "",
        "title": "Test event 4",
        "id": "824",        
        "start": "2012-11-27 6:00:00",
        "end": "2012-11-27 7:00:00"
    }
]

Let me know if you have any issues or something to add!

Cheers,
Chris


Posted

in

, ,

by

Comments

40 responses to “FullCalendar Example with Client-Side Event Updates”

  1. Alex Shabetayev (@alechko03) Avatar

    Hey Chris,

    Thank you for this, its just what I have been looking for. Great work really explains the FullCalendar capabilities!

    Like

    1. Chris Owens Avatar
      Chris Owens

      No worries Alex, thanks for the feedback!

      Like

  2. apelbapaw4u Avatar

    how to remove the event??

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey Apelbapaw3u,

      Check out this link. http://arshaw.com/fullcalendar/docs/event_data/removeEvents/. The documentation is pretty good there.

      Cheers,
      Chris

      Like

  3. Raül Avatar

    How to do that the events persist? I mean, I create new events, they are shown but when I go out and back (refresh page, go out anb back to the site, etc) they are disappeared.

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey Raul,

      To store the events you’ll probably want to wire it up to a backend of some sort or look into HTML5 storage depending on what you’re after. Alternatively, FullCalendar does support Google Calendar. I haven’t tried it but if it’s probably a lot quicker to setup if you don’t need a fully fledged app. Check out this link for more info: http://arshaw.com/fullcalendar/docs/google_calendar/.

      Like

  4. Shanmuga Sankara Pandian Muthu Avatar

    Nice Jobs..its very helpful. Thanks

    Like

  5. Kala Kala Avatar
    Kala Kala

    Nice ! How to remove the event just dropped from the event list (i want to be able to drop an event only once). Can we reverse an event to the events list ?

    Thanks you and sorry for my english

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey Kala,

      No worries. If I’m understanding you right, all you’d need to do is an a line to the external_event_dropped event. Just remove the matching template from the id. You might be better off redoing the event list if you’re going to do much with it though, this is really just a mock-up. If I were to do it all again, I’d probably take a look at AngularJS – you could do some really nice stuff wiring this up as a directive.

      Let me know if you need any more info.

      Cheers,
      Chris

      Like

  6. James Klein Avatar

    I’m using FullCalendar out of the box following their documentation. I’m able to pass json to the view with my Event’s controller with no problem but I can’t seem to do an ajax post request as a PUT to update the event after moving it around the calendar.
    I’m getting this message
    > PUT http://localhost:3001/events/2 406 (Not Acceptable)

    and the code that I’ve dropped into my calendar.js is as follows
    editable: true,
    eventDrop: function(event,dayDelta,minuteDelta,allDay,revertFunc) {
    $.ajax({
    type:”PUT”,
    url: “/events/”+event.id
    });
    }
    I know I’m not passing any data right now but I just want to get the post working.
    Thanks in advance and any help is appreciated.

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey James,

      I’m going to need some more info to be able to help, this is probably server side.

      Is it just put that’s affected or is post being rejected as well? What stack etc?

      If you can you provide a link or fiddle I’ll take a quick look? Might also be worth trying to set to set the content type.

      Cheers,
      Chris

      Like

      1. James Klein Avatar

        Hey Chris,
        I meant to reply to this awhile ago. Not sure what the fix was back then but here is my updated code incase it helps anyone else. Notice the “.json” which may have been the problem.

        eventDrop: function(event,dayDelta,minuteDelta,allDay,revertFunc) {
        console.log(event.id);
        $.ajax({
        url: “/events/” + event.id +”.json”,
        type: ‘PUT’,
        data: { days_moved: dayDelta },
        success: function(result) {
        },
        error: function() {
        console.log(“Failed to update event”);
        }
        });
        },

        Cheers,
        James

        Like

      2. Chris Owens Avatar
        Chris Owens

        Thanks for updating James, glad you got it working!

        Like

  7. irham Avatar
    irham

    How do I add a touch screen slide transition for next and prev in fullcalendar, thanks

    Like

  8. Karteek Kommana Avatar

    Hi Chris,
    It was nice work for fullCalendar. I appreciate your work. I wonder is it possible to save the events in Database and show it agian when ever the web page is loaded? I want to have a event calendar in my project where user can able to create event and see it when ever they visit the page again.
    Thanks
    Karteek

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey Karteek,

      Definitely possible, take a look at event sources:

      http://arshaw.com/fullcalendar/docs/event_data/Event_Source_Object/
      http://arshaw.com/fullcalendar/docs/event_data/eventSources/

      All you really need to do is point it to a url on your site that returns the events as JSON. The doco there is fairly good, but definitely let me know if you run into issues.

      Cheers,
      Chris

      Like

  9. Lugisani Muthige Avatar
    Lugisani Muthige

    thank you somuch chris

    Like

  10. Lugisani Muthige Avatar
    Lugisani Muthige

    There seems to a bug on the calendar interface, when i navigate through dates there is a blue portion that comes up from the buttons to the date title, its like one that’s meant for editing the date i’m not sure… and when i add events on the monthly view they don’t appear on the week and day view.

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey Lugisana, I can’t seem to replicate this sorry, what browser are you using?

      Like

  11. Lugisani Muthige Avatar
    Lugisani Muthige

    google chrome

    Like

  12. Gary Avatar
    Gary

    Chris, just want to say thanks, this is an excellent foundation and starting point, thanks for the framework to get up and running with understanding of how to implement and tool the calendar.

    Like

  13. Gary Avatar
    Gary

    Chris, one more thing, wondering if you’ve encountered this in your work with this but is there an easy way to incorporate the repeat event, say, I want to set an event that I am on call every 3rd week of every month? thanks again

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey Gary,

      Sorry about the late reply. When I did this I think I ended up handling repeated events server side. My use case was a bit unusual, but for most normal situations this guys has a pretty detailed description: http://fajitanachos.com/Fullcalendar-and-recurring-events/

      Let me know if you need any more info.

      Like

  14. Gary Avatar
    Gary

    Chris, you are differently the master and a very kewl person to keep this up and provide us with your knowledge. a million thanks, because without it, I know I would spend countless hours getting to this point. thank you very much!!

    Like

  15. Peter Kaye Avatar

    Thanks for this post which has opened my eyes to Full Calendar features I’d not been aware of.

    I’d like to render the event id in the HTML as an HTML ID or similar so that I can pick it up in an Microsoft Access application. For example

    Peter Jones

    where 99023 is the MySQL ID for the event. Is this possible and if so could you point me in the right direction ? Thanks again.

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey Peter,

      Sorry, I’m not too sure what you mean? Do you want to have it appear in the event so that users can can see it, or just have it as a data attribute on the element?

      Cheers,
      Chris

      Like

      1. Peter Kaye Avatar

        Thanks Chris.
        No I don’t want the id to appear on the calendar, just in the HTML so that my VBA screen scrape can read it and find the correct calendar event record.

        Like

  16. Peter Kaye Avatar

    I should have realised that HTML gets stripped from WP comments ! The missing code relates to the Full Calendar Div which wraps the event and has a class of fc-event-inner.

    Like

  17. Harsh Jhaveri Avatar

    Hello, I am using Full Calendar in my pages, but there is some issues as if i am selecting any records then that day selected but if i am click out side of it, then it will be unselect, even if i m click on page scroll then also it unselect my selection.
    IS there any way where we can default selected particular day which we clicked.

    Please advice

    thanks

    Like

  18. ronan haughey Avatar

    Hi there. How would I go about having templates already on the page, without having to create them? many thanks

    Like

  19. Don Martin Avatar

    I am interested in retieving events from a file and tried you eventsource with calendar_events.json. I was not able to get it to work. So I downloaded and ran your zip package. Only the first event is displayed. Has the json spec change in the last year?

    …Don

    Like

  20. rafatc Avatar
    rafatc

    Wow, that’s great ! Thanks a lot, This really helped me out.

    Like

  21. anitha Avatar
    anitha

    Is it possible to do recurring event in fullcalendar?

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey Anitha,

      You can definitely implement them server side, but I don’t think there’s anything specifically for doing it within fullcalendar. Check out this stackoverflow post for a bit more info on how to go about it: http://stackoverflow.com/a/15206043/522859

      Like

  22. Cesar Avatar
    Cesar

    Hi Chris , I have a doubt , was reviewing your contribution and I feel sensational, I have just one question , and I take several days looking for information about it and I can not take this, I need you to keep an event that remains assigned a color but not I have idea how to pass this parameter by Jason respect for me to load data into the full calendar from a MySQL DB can be done ?

    Thank You

    atte

    Cesar

    Like

  23. Jesùs Avatar
    Jesùs

    Hi Chris,

    You definitely saved one poor soul today from getting insane 🙂
    Just one remark:
    your function get_uni_id() returns the UNIX timestamp in milliseconds,
    because Math.floor(Math.random()) always equals 0,
    but hey, I guess that return value is unique enough.

    Cheers,
    Jesús

    Like

  24. Jalaal Charaf Avatar
    Jalaal Charaf

    Hi Chris,

    Really a useful bit of coding. Nice work!

    I cannot get it to work with the newer version of fullcalendar though. Have run into many errors. Did anyone do any updates on this code?

    Thanks,

    Jaime

    Like

    1. Chris Owens Avatar
      Chris Owens

      Hey Jamie,

      Thanks for the reply hey, unfortunately this was all done on the original fullcalendar. I’m not too sure what’s changed with the updates. I’d tags a look but I’m overseas for a few weeks.

      Please let me know if there’s anything that needs to be added to the party and I’m update it.

      Cheers,
      Chris

      Like

  25. Maite Lopez Avatar
    Maite Lopez

    Good project. I have two question,

    1.- I don´t see in your code where you say that de time and the content have different color (time darker than content). can you help me to find them?
    2.- I need my date and border in one color (read from DB) and the content in another color (also read from DB). Do you know if it si possible??

    Like

    1. Maite Lopez Avatar
      Maite Lopez

      Sorry, I mean TIME insted of DATE

      Like

Leave a Reply to Lugisani Muthige Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at WordPress.com

%d bloggers like this: