JDeveloper 12.2.1.4: af:chooseDate

The new JDeveloper 12.2.1.4 has added an enhancement an a new feature to the af:chooseDate component. We are looking at both in this article.

Enhancement

The enhancement is that you can now set a default date which is shown as the selected date when the field you show the af:chooseDate for is empty. In the older JDeveloper versions, the selected date was always the current date. The image below shows the situation of how the af:chooseDate component looks like:

The af:inputText ‘Datum’ is not set and because of this, the af:chooseDate shows the current date (when I took the picture) as the selected date. Problem is, that there are use cases where you don’T want the current date to be the selected date, e.g. your use case might want to show the next Friday after the current date as the selected date. This was not easily possible.

Now, the enhancement to the af:hcooseDate component allows us to set a default date via the property ‘defaultValue’. When set to a literal value, this will be parsed as “yyyy-MM-dd hh:mm:ss” or “yyyy-MM-dd”.

I added an af:inputdate ‘Set DefaultDate’ to allow selection of a date which then will be used as the default date in the af:chooseDate for the ‘Datum’ field. The current date is marked with gray and the date set in the ‘Set Default Date’ is shown as the selected date.

As you see, the ‘Datum’ field is still empty. If you select a date like ‘12/20/2019’ you get

Sample Code

<af:inputDate label="Set Default Date:"
     Nhn ng  value="#{bindings.defaultDate1.inputValue}" id="id2"
     autoSubmit="true"/>
<af:spacer id="s1" height="10px"/>
<af:panelGroupLayout id="pgl2" layout="horizontal">
<af:inputDate label="Datum" id="id1" chooseId="cd1"/>
<af:chooseDate id="cd1"
    defaultValue="#{bindings.defaultDate1.inputValue}"
    partialTriggers="id2"/>

New Feature: “Multiple Date Selection”

The af:chooseDate component has another feature added. Now you can select multiple dates at once. This feature is very handy as you can now use one af:chooseDate to get a start date and an end date or date ranges. The image below shows the component with multiple dates selected.

The interesting thing is, that there is no implementation for this hardcoded in the component. Meaning is that we, the developers, need to implement this feature ourselves. For this ADF provides two new client events ‘load’ and ‘dateSelection’ that are triggered by the af:chooseDate component. We use these client events to implement the multi-select feature. The load event can be used to pass an array of dates to the component which are then shown as selected. This event is triggered when the component loads, as the name implies. The dateSelection event is triggered each time a user selects a date. It passes information about the keyboard state so that we can handle range selection.

To make it easier, the ADF Rich Client Demo has a sample implementation of the needed JavaScript code which I used as the base of my implementation:

/**
 * Shows a popup from an "action" type event.
 * @param {AdfActionEvent} actionEvent the event being handled
 */
var dates = [];
var minDate;
var maxDate;

function dateSelectionEventHandler(event) {
    var eventSource = event.getSource();
    var selectedDate = event.getSelectedDate();
    var modifier = event.getModifiers();

    if (modifier.indexOf(AdfRichChooseDate.MULTI_SELECTION) !=  - 1) {
        dates.push(selectedDate);
    }
    else if (modifier.indexOf(AdfRichChooseDate.RANGE_SELECTION) !=  - 1) {
        if (!minDate || (minDate.getTime() > selectedDate.getTime())) {
            minDate = selectedDate;
        }
        if (!maxDate || (maxDate.getTime() < selectedDate.getTime())) {
            maxDate = selectedDate;
        }
        var timeDiff = Math.abs(maxDate.getTime() - minDate.getTime());
        var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24)) + 1;
        dates = []
        for (var i = 0;i < diffDays;i++) {
            var selDate = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate() + i, 0, 0, 0, 0);
            if (!eventSource.isDisabled(selDate))
                dates.push(selDate)
        }
    }
    else if (modifier.indexOf(AdfRichChooseDate.SINGLE_SELECTION) !=  - 1) {
        minDate = null;
        maxDate = null;
        dates = []
        dates.push(selectedDate)
    }
    eventSource.setSelectedDates(dates);
}

function chooseDateLoadEventHandler(event) {
    var eventSource = event.getSource();
    eventSource.setSelectedDates(dates);
}

function processSelectedDates(event) {
    component = event.getSource();
    AdfCustomEvent.queue(component, "processSelectedDates", 
    {
        payload : dates
    },
    true);
    event.cancel();
}

There are three JavaScript funtions:

  1. dateSelectionEventHandler(event) handles the selection of one or more dates
  2. chooseDateLoadEventHandler(event) handles the inital load of hte component and allows us to set dates as selected
  3. processSelectedDates(event) is the funtion which passes the selected dates to a server event

The functions are added to the af:chooseDate compponent as client listerner

<af:chooseDate id="cd2" clientComponent="true">
    <af:clientListener type="dateSelection" 
        method="dateSelectionEventHandler"/>
    <af:clientListener type="load" method="chooseDateLoadEventHandler"/>
</af:chooseDate>

To pass the selected dates to a server event a button is used like

<af:button text="Selected Dates" id="b2">
    <af:clientListener method="processSelectedDates" type="action"/>
    <af:serverListener type="processSelectedDates"
        method="#{viewScope.ChooseDateBean.procressSelectedDates}"/>
 </af:button>

The image below shows the selected dates once the button ‘Selected Dates’ is clicked.

This JavaScript function simply passes the array of selected dates as payload from the client to the server. There the dates are just stored in a bean variable. This variable is used to show the dates in an af:outputText.

The same works for a range selection as shown below

And after the button ‘Selected Dates’ is clicked we get

The sample can be downloaded from GitHub BlogChooseDate or directly as a zip. The sample is written using JDeveloper 12.2.1.4 and doesn’t use any DB connection.