Creating Custom Date Selectors in Oracle APEX: Month, Quarter, and Year

Introduction

Ever craved more control over date pickers in your Oracle APEX applications? The buit-in options might not always offer the perfect fit. This post explores a technique to create custom date selectors for specific needs:

  • Month Selector  -> choose just month and year
  • Quarter Selector -> select quarter and year
  • Year Selector -> pick only the year 

Crafting Custom Selectors: 

Create Text Fields:
  • We'll create three page items of type Text Field : P2_MONTH, P2_QTR and P2_YEAR
Add Calendar Buttons with jQuery:
  • We'll leverage jQuery to dynamically add calendar buttons next to each text field. These buttons trigger the datepicker functionality.
  • In the Post Text attribute of each item, add the following code:
  • For P2_MONTH
<button
type="button"
style="height:100%"
class="a-Button a-Button--calendar"
onclick="$('#P2_MONTH').datepicker('show');">
<span class="a-Icon icon-calendar" >
</span>
</button>

  • For P2_QTR
<button
type="button"
style="height:100%"
class="a-Button a-Button--calendar"
onclick="$('#P2_QTR').datepicker('show');">
<span class="a-Icon icon-calendar" >
</span>
</button>

  • For P2_YEAR
<button
type="button"
style="height:100%"
class="a-Button a-Button--calendar"
onclick="$('#P2_YEAR').datepicker('show');">
<span class="a-Icon icon-calendar" >
</span>
</button>

 Configure Datepickers (JavaScript):
  • JavaScript is used to configure individual datepicker behaviours for each fields.
  • Navigate to Page Attributes and add the following code to the Execute when page loads section
$('#P2_MONTH').datepicker({
changeMonth: true,
changeYear: true,
showButtonPanel: true,
dateFormat: 'yy-mm',
yearRange: '2020:2030',
onClose: function(dateText, inst) {
var month = $("#ui-datepicker-div .ui-datepicker-month :selected").val();
var year = $("#ui-datepicker-div .ui-datepicker-year :selected").val();
$(this).datepicker('setDate', new Date(year, month, 1));
},
beforeShow: function(input, inst) {
var datestr;
if ((datestr = $(this).val()).length > 0) {
year = datestr.substring(0, 4);
month = datestr.substring(5, 7);
$(this).datepicker('option', 'defaultDate', new Date(year, month - 1, 1));
$(this).datepicker('setDate', new Date(year, month - 1, 1));
$(".ui-datepicker-calendar").hide();
}
}
});


$('#P2_QTR').datepicker({
dateFormat: 'M-yy',
changeMonth: true,
changeYear: true,
showButtonPanel: true,
yearRange: '2020:2030',
monthNamesShort: ["", "", "Q1", "", "", "Q2", "", "", "Q3", "", "", "Q4"],
onClose: function(dateText, inst) {
var month = $("#ui-datepicker-div .ui-datepicker-month :selected").val();
var year = $("#ui-datepicker-div .ui-datepicker-year :selected").val();
$(this).datepicker('setDate', new Date(year, month, 1));
},
beforeShow: function(input, inst) {
var datestr;
if ((datestr = $(this).val()).length > 0) {
var year = datestr.substring(datestr.length - 4, datestr.length);
var qtr = datestr.substring(0, 2);
var month;
if (qtr == 'Q1')
month = '03';
else if (qtr == 'Q2')
month = '06';
else if (qtr == 'Q3')
month = '09';
else if (qtr == 'Q4')
month = '12';
$(this).datepicker('option', 'defaultDate', new Date(year, month - 1, 1));
$(this).datepicker('setDate', new Date(year, month - 1, 1));
$(".ui-datepicker-calendar").hide();
}
},
afterShow: function(dateText, inst) {
var keepMonths = [];
for (i = -1; i < 12; i += 3) {
keepMonths.push(i);
}
$(".ui-datepicker-month option").each(function() {
if ($.inArray(parseInt(this.value), keepMonths) < 0) {
$(this).remove();
}
});
}
}).next('button').text('Show calendar').button({
icons: {
primary: 'ui-icon-calendar'
},
text: false
});

$.datepicker._updateDatepicker_original = $.datepicker._updateDatepicker;
$.datepicker._updateDatepicker = function(inst) {
$.datepicker._updateDatepicker_original(inst);
var afterShow = this._get(inst, 'afterShow');
if (afterShow)
afterShow.apply((inst.input ? inst.input[0] : null));
}



$('#P2_YEAR').datepicker({
changeYear: true,
showButtonPanel: true,
dateFormat: 'yy',
yearRange: '2020:2030',
onClose: function(dateText, inst) {
var year = $("#ui-datepicker-div .ui-datepicker-year :selected").val();
$(this).datepicker('setDate', new Date(year, 1));
},
beforeShow: function(input, inst) {
var datestr;
if ((datestr = $(this).val()).length > 0) {
year = datestr
$(this).datepicker('option', 'defaultDate', new Date(year, 1));
$(this).datepicker('setDate', new Date(year, 1));
$(".ui-datepicker-calendar").hide();
$(".ui-datepicker-month").hide();
}
},
afterShow: function(dateText, inst) {
$(".ui-datepicker-month").hide();
}
});

Style Enhancements(CSS):
  • Add the following CSS to the Inline CSS attribute of the page

    .ui-datepicker-calendar,
    .ui-datepicker-next,
    .ui-datepicker-prev {
    display: none;
    }

    The Final Result:
    • Here is how the custom date selectors look when the page is run.








    This approach provides a solid starting point for further customisation. 

    This Post reflects the learning and experience I gained from working on various projects alongside my talented team members.