| Tweet |
If you've used Visualforce input fields backed by a Date or DateTime sobject field, one thing you'll have noticed is the date range isn't that helpful. For example, the screenshot below is from my developer edition and the starting year is 2011.
This is fine for opportunities, cases, campaigns etc., that have dates in
the future, but less than useful when recording a date in the past - for
example year of birth. There's a couple of options here. The first
is to use some javascript on the page to tweak the setup of the date picker.
Not a solution I'd recommend, as a change to the underlying
implementation would break the page.
The other option is to use a custom date picker. I favour the Design2Develop implementation, as a lot of the others have style class names that
overlap with the Salesforce implementation, which could cause problems if I
wanted to combine both on the same page.
The first thing to do is get the zip file from the download page and then upload it as a static resource to your Salesforce
organization. I chose the name JSCalendar - if you choose a different
one, change the $Resource entries in the sample code.
Next, create the Visualforce page and add following lines to include the core
Javascript and styling:
(UPDATE 09/01/2014 - the latest zip needs the calendar folder specified as the
location for the JavaScript and CSS - if you are having problems make sure
these your imports match these lines)
<apex:includeScript value="{!URLFOR($Resource.JSCalendar,’calendar/calendar.js')}"/>
<apex:stylesheet value="{!URLFOR($Resource.JSCalendar,’calendar/calendar_blue.css')}" />
I've gone for the blue style, but there are several others in the zip file. Next, define the date format that you'll be using - this is achieved by implementing the fnSetDateFormat function:
function fnSetDateFormat(oDateFormat)
{
oDateFormat['FullYear']; //Example = 2007
oDateFormat['Year']; //Example = 07
oDateFormat['FullMonthName']; //Example = January
oDateFormat['MonthName']; //Example = Jan
oDateFormat['Month']; //Example = 01
oDateFormat['Date']; //Example = 01
oDateFormat['FullDay']; //Example = Sunday
oDateFormat['Day']; //Example = Sun
oDateFormat['Hours']; //Example = 01
oDateFormat['Minutes']; //Example = 01
oDateFormat['Seconds']; //Example = 01
var sDateString;
// Use dd/mm/yyyy format
sDateString = oDateFormat['Date'] +"/"+ oDateFormat['Month'] +"/"+ oDateFormat['FullYear'];
return sDateString;
}
Next, define the function that will manage the integration between the date picker and the input element. This takes two parameters - the object that fired the calendar popup (e.g. an image or button) and the id of the input element that contains the date. This function will be called when the picker is displayed, and is responsible for extracting the current value from the input element and passing that to the library function.
function initialiseCalendar(obj, eleId)
{
var element=document.getElementById(eleId);
var params='close=true';
if (null!=element)
{
if (element.value.length>0)
{
// date is formatted dd/mm/yyyy - pull out the month and year
var month=element.value.substr(3,2);
var year=element.value.substr(6,4);
params+=',month='+month;
params+=',year='+year;
}
}
fnInitCalendar(obj, eleId, params);
}
Finally, add an input component. Its possible to change the standard behaviour of the apex:inputField using javascript to tie to to the custom picker as opposed to the standard, but again this is a fragile solution and would preclude using standard and custom on the same, so I prefer use an apex:inputText instead. As can be seen, the object that is passed to the initialiseCalendar function is the input field that is also identified by the id parameters - I could change the function to take a single parameter, but if I then wanted to have an image that is clicked on to open the calendar I'd be out of luck. I've made this the onmouseover event handler so that it opens in similar way to the standard picker.
<apex:inputText id="startdate" size="10" value="{!Campaign.StartDate}" onmouseover="initialiseCalendar(this, '{!$Component.startdate}')"/>
Here's a screen shot of the new picker:
There's a fair bit more you can do to customize this picker - check out the docs on the download page.
For the sake of completeness here is the full markup of the Visualforce page:
<apex:page standardController="Campaign">
<apex:includeScript value="{!URLFOR($Resource.JSCalendar,’calendar/calendar.js')}"/>
<apex:stylesheet value="{!URLFOR($Resource.JSCalendar,’calendar/calendar_blue.css')}" />
<apex:pageMessages />
<apex:form id="frm">
<apex:pageblock id="pb">
<apex:pageBlockButtons >
<apex:commandButton value="Save" action="{!save}" />
<apex:commandButton value="Cancel" action="{!Cancel}" />
</apex:pageBlockButtons>
<apex:pageBlockSection id="pbs">
<apex:inputField value="{!Campaign.Name}" />
<apex:inputText id="startdate" size="10" value="{!Campaign.StartDate}" onmouseover="initialiseCalendar(this, '{!$Component.startdate}')"/>
<apex:inputText id="enddate" size="10" value="{!Campaign.EndDate}" onmouseover="initialiseCalendar(this, '{!$Component.enddate}')"/>
</apex:pageBlockSection>
</apex:pageblock>
</apex:form>
<script>
function fnSetDateFormat(oDateFormat)
{
oDateFormat['FullYear']; //Example = 2007
oDateFormat['Year']; //Example = 07
oDateFormat['FullMonthName']; //Example = January
oDateFormat['MonthName']; //Example = Jan
oDateFormat['Month']; //Example = 01
oDateFormat['Date']; //Example = 01
oDateFormat['FullDay']; //Example = Sunday
oDateFormat['Day']; //Example = Sun
oDateFormat['Hours']; //Example = 01
oDateFormat['Minutes']; //Example = 01
oDateFormat['Seconds']; //Example = 01
var sDateString;
// Use dd/mm/yyyy format
sDateString = oDateFormat['Date'] +"/"+ oDateFormat['Month'] +"/"+ oDateFormat['FullYear'];
return sDateString;
}
function initialiseCalendar(obj, eleId)
{
var element=document.getElementById(eleId);
var params='close=true';
if (null!=element)
{
if (element.value.length>0)
{
// date is formatted dd/mm/yyyy - pull out the month and year
var month=element.value.substr(3,2);
var year=element.value.substr(6,4);
params+=',month='+month;
params+=',year='+year;
}
}
fnInitCalendar(obj, eleId, params);
}
</script>
</apex:page>