30 Sept 2016

Time Picker Declarative Component

Recently I came across the following requirement: there is a Timestamp attribute in an entity and users should be able to modify only time part (hours and minutes) of the attribute value.

Apparently,  this requirement could be implemented with a kind of a time-picker component allowing  to input hours and minutes but hiding the date part. There is date-time-picker (af:inputDate) component in ADF Faces, but there is no just time-picker. The solution is to make a declarative component out of two input-number-spinboxes (one for hours, one for minutes):

<af:xmlContent>
    <afc:component>
        <afc:description/>
        <afc:display-name>TimePicker</afc:display-name>
        <afc:attribute>
            <afc:attribute-name>valueBinding</afc:attribute-name>
            <afc:attribute-class>
              oracle.jbo.uicli.binding.JUCtrlAttrsBinding
            </afc:attribute-class>
        </afc:attribute>
        <afc:attribute>
            <afc:attribute-name>label</afc:attribute-name>
            <afc:attribute-class>java.lang.String</afc:attribute-class>
        </afc:attribute>
    </afc:component>
</af:xmlContent>
<af:panelLabelAndMessage label="#{attrs.label}" id="pll1">
    <af:panelGroupLayout id="dc_pgl1" layout="horizontal">
        <af:inputNumberSpinbox simple="true" id="dc_ins1"
                               value="#{backingBeanScope.timePicker.hours}"
                               minimum="0" maximum="23"/>
        <af:spacer width="10" height="10" id="dc_s1"/>
        <af:inputNumberSpinbox simple="true" id="dc_ins2"
                               value="#{backingBeanScope.timePicker.minutes}"
                               minimum="0" maximum="59">
        </af:inputNumberSpinbox>
    </af:panelGroupLayout>
</af:panelLabelAndMessage>


Note, that values for the input-number-spinboxes are provided by backing bean properties. The timePicker backing bean is responsible for extracting hours and minutes from the timestamp value of the attribute value binding which is passed to the component as valueBinding attribute. This is not a big deal with Java 8 Date/Time API:
    private JUCtrlAttrsBinding getValueBinding() {
       return (JUCtrlAttrsBinding) getAttributes().get("valueBinding");
    }


    private LocalDateTime getTime() {
        Timestamp timeStampTime =
            (Timestamp) getValueBinding().getInputValue();
        return timeStampTime.toLocalDateTime();
    }


    public Integer getHours() {
        return getTime().getHour();
    }


    public Integer getMinutes() {
        return getTime().getMinute();
    }


On the other hand, the setters of hours and minutes of the backing bean properties create a new Timestamp instance out of hours and minutes and set it as an input value of the valueBinding attribute:
    public void setHours(Integer value) {
        setTime(value, getMinutes());
    }


    public void setMinutes(Integer value) {
        setTime(getHours(), value);
    }

    private void setTime(int hours, int minutes) {
      LocalDateTime time =
        LocalDateTime.of(getTime().toLocalDate(), LocalTime.of(hours, minutes));

      getValueBinding().setInputValue(Timestamp.valueOf(time));
    }

The sample application for this post, containing the TimePicker declarative component, is available here. It requires JDeveloper 12.2.1.1.

That's it!




No comments:

Post a Comment

Post Comment