I often use jQuery plugins for front-end functionality in web applications. This requires me to write code like this, where I am assigning a function to a an object property:
var trainingDiary = $("#training_diary").fullCalendar({
dayClick: function(date, allDay, jsEvent, view) {
var title = prompt('Event Title:');
var dayObj = $(this);
//console.log($(this));
if (title) {
$.ajax({
url: "/app_dev.php/addtrainingday",
global: false,
type: "POST",
data: "dayNo=" + date.getDate(), //returns day of month. getDay() returns day of week
async:true,
success: function(msg) {
trainingDiary.fullCalendar('renderEvent',
{
title: title,
start: date,
allDay: allDay,
backgroundColor:'#cccccc'
},
true // make the event "stick" across calendar pages
)
dayObj.css({'background-color':'#339933','background-image':'url()'})
console.log(msg.valueOf());
} //end ajax success
})
} else {
trainingDiary.fullCalendar('unselect');
}
},
theme: true,
header: {left:'title',
center: '',
right: 'today prev next'},
firstDay:1
});
The code becomes hard to read and maintain as there is now a success function within an ajax function within yet another function. My question is how can I improve the code so that 'dayClick: function(...) can call a function defined outside of the fullCalendar call. In this case, fullCalendar is a jQuery plugin.
UPDATED CODE:
// Directives for JSLint
/*global console, prompt, $, ROOT_URL */ // declaration of global variables used
/*jslint unparam: true, sloppy: true, white: true */ // disable less useful checks
//create a closure for private scope
( function() {
var calendarOptions, // object, options for calendar diary
trainingDiary, // object, training diary using jQuery plugin fullCalendar()
bgColour = '#339933';
// Function: onDayClick(day, allDay, jsEvent, view)
// Callback for the selection of a day in the calendar.
//
// Parameters:
// date - type?, description?
// allDay - type?, description?
// jsEvent - type?, description?
// view - type?, description?
function onDayClick(date, allDay, jsEvent, view) {
var date2 = new Date(date.getFullYear(), date.getMonth(), date.getDate()+1),
todaysEvents = trainingDiary.fullCalendar('clientEvents', function(event) {
return event.start >= date && event.start < date2;
}),
title, // string, event title, input by user
dayObj = $(this), // object, jQuerified DOM element
ajaxOptionsAdd, // object, options for AJAX call to addtrainingday script
ajaxOptionsRemove; // object, options for AJAX call to addtrainingday script
//NESTED AJAX CALLS - NESTED TO RETAIN REQUIRED PARAMS IN CLOSURE SCOPE
// Function: onAjaxSuccessAdd(msg)
// Callback for a successful AJAX call to server-side addtrainingday script.
//
// Parameter:
// msg - string, message received from server
function onAjaxSuccessAdd(msg) {
var event = {
title: title,
start: date,
allDay: allDay,
backgroundColor: bgColour
};
//render the event on the calendar
trainingDiary.fullCalendar(
'renderEvent',
event,
true // make the event "stick" across calendar pages
);
dayObj.css({
'background-color':bgColour,
'background-image':'url()'
}); // added missing semicolon
console.log(msg.valueOf());
} // end of onAjaxSuccessAdd declaration
// Function: onAjaxSuccessRemove(msg)
// Callback for a successful AJAX call to server-side removetrainingday script.
//
// Parameter:
// msg - string, message received from server
function onAjaxSuccessRemove(msg) {
trainingDiary.fullCalendar('removeEvents',todaysEvents.id);
dayObj.css({
'background-color':'#FFFFFF',
'background-image':'url()'
}); // added missing semicolon
console.log(msg.valueOf());
} // end of onAjaxSuccessRemove declaration
// AJAX CALL OPTIONS
ajaxOptionsAdd = {
url: ROOT_URL+"addtrainingday",
global: false,
type: "POST",
// getDate() returns day of month. getDay() returns day of week
data: "date=" + $.fullCalendar.formatDate(date, 'yyyy-MM-dd hh:mm:ss'),
async: true,
success: onAjaxSuccessAdd
};
ajaxOptionsRemove = {
url: ROOT_URL+"removetrainingday",
global: false,
type: "POST",
// getDate() returns day of month. getDay() returns day of week
data: "date=" + $.fullCalendar.formatDate(date, 'yyyy-MM-dd hh:mm:ss'),
async: true,
success: onAjaxSuccessRemove
};
// DAYCLICK EXECUTION LOGIC
if (todaysEvents.length > 0 ) {
$.ajax(ajaxOptionsRemove);
return;
}
title = prompt('Event Title:');
if (title) {
$.ajax(ajaxOptionsAdd);
} else {
trainingDiary.fullCalendar('unselect');
}
} // end of onDayClick declaration
// CALENDAR INITIIALIZATION CODE
calendarOptions = {
dayClick: onDayClick,
theme: true,
header: {
left: 'title',
center: '',
right: 'today prev next'
},
firstDay: 1,
eventRender: function (event, element) {
element.removeClass('fc-corner-right fc-corner-left'); //removes border round the event
}
};
trainingDiary = $("#training_diary").fullCalendar(calendarOptions);
}() ); //end of and call of closure