2

Have a very simple VF page that allows the end user to either set an expiration date, or choose the number of days until the expiration. What I wanted to do was update the other field when one was updated. For example, if they set the expiration date field, the number of days field is automatically filled with the number of days between today and the date they chose. Conversely, I would like to do the same for the number of days field, if they chose a number of days, I would like the date field populated with today + number of days they chose.

I chose to use JS Remoting for this. After implementing I realized that the trip to the server, although much quicker due to JS remoting, may not be necessary at all since I'm really just adding and subtracting dates in Apex. Here are the applicable snippets.

VF/JS

<apex:page showHeader="true" sidebar="true" standardController="POC__c" extensions="NewPOCExtensionController">

<apex:includeScript value="{!URLFOR($Resource.jquery, 'jquery-ui-1.10.2.custom/js/jquery-1.9.1.js')}" />
<apex:includeScript value="{!URLFOR($Resource.jquery, 'jquery-ui-1.10.2.custom/js/jquery-ui-1.10.2.custom.min.js')}" />

<script>

var j$ = jQuery.noConflict();

j$(function() {

    var dateField = j$('[id$=date]');
    var daysField = j$('[id$=days]');

    dateField.keypress(function(e) {
        if((e.which < 48 || e.which > 57) && e.which != 8){
            e.preventDefault();
        }
    });
    daysField.keypress(function(e) {
        console.log('Key Press: ' + e.which);
        if((e.which < 48 || e.which > 57) && e.which != 8){
            e.preventDefault();
        }
    });

    dateField.change(function(e) {
        e.preventDefault();
        if(j$(this).val().length != 0 ) {
            NewPOCExtensionController.updateNumberOfDays(j$(this).val(), function(result, event) {

                console.log(result);
                if (event.status) {//if successful
                    daysField.val(result);
                }
            });
        }
    });


    daysField.keyup(function(e) {

            if((e.which < 48 || e.which > 57) && (e.which < 96 || e.which > 105 ) && (e.which != 8)){
                return;
            }
            if(e.which == 8 && j$(this).val().length == 0){
                dateField.val('');
                return;
            }

            NewPOCExtensionController.updateExpirationDate(j$(this).val(), function(result, event) {
                if (event.status) {//if successful
                    dateField.val(result);
                }
            });
    });

});


</script>





    <apex:form >
    <apex:sectionHeader title="New POC Extenstion" subtitle="Extension for " />
    <apex:pageBlock title="Extension Details">

        <apex:pageBlockButtons location="bottom">
            <apex:commandButton Value="Submit Extension for Approval" action="{!createExtension}"/>
        </apex:pageBlockButtons>

        <apex:pageBlockSection title="Extension Details" columns="1">

            <apex:pageBlockSectionItem >
                <apex:outputLabel value="New Expiration Date" for="date"/>
                <apex:inputField value="{!newExtension.New_Requested_Expiration__c}" id="date"/>
            </apex:pageBlockSectionItem>

            <apex:pageBlockSectionItem >
                <apex:outputLabel value="OR" for="or"/>
                <apex:outputText value="" id="or"/>
            </apex:pageBlockSectionItem>

            <apex:pageBlockSectionItem >
                <apex:outputLabel value="Number of Days" for="days"/>
                <apex:inputText value="{!numberOfDays}" id="days"/>
            </apex:pageBlockSectionItem>

        </apex:pageBlockSection>

    </apex:pageBlock>
    </apex:form>

</apex:page>

Controller Methods

@RemoteAction
    public static Integer updateNumberOfDays(string dt) {

        Date today = system.today();
        Date myDate = Date.parse(dt);
        Integer numDays = today.daysBetween(myDate);
        return numDays;
    }

    @RemoteAction
    public static String updateExpirationDate(Integer numDays) {

        Date today = system.today();
        Date expDate = today.addDays(numDays);
        DateTime expDateTime = DateTime.newInstance(expDate, Time.newInstance(0, 0, 0, 0));
        String dateStringToReturn = expDateTime.format('M/d/yyyy');
        return dateStringToReturn;
    }

This works very well and I really don't mind doing it this way, but the perfectionist in me is telling me that there is an easier way to do this completely Client side which would of course be more efficient. My Js and jQuery is decent, but certainly not an expert, my research on date manipulation showed that it's a bit clunky, and not always clean. I thought I would ask the community for some input.

Anyone have a way to do this completely client side?

2 Answers 2

1

I love such solutions based on almost pure visualforce. Here I've tried to use apex:variable for date and number claculations. The only javascript used here is for locale date formatting and setting new values to the field:

<apex:variable value="{!TODAY()}" var="newDate" />
<apex:variable value="{!0}" var="newNumber" />

<apex:pageBlock title="Extension Details">
    <apex:pageBlockSection title="Extension Details" columns="1">
        <apex:pageBlockSectionItem >
            <apex:outputLabel value="New Expiration Date" for="expdate"/>
            <apex:inputField value="{!test1obj.MyDate__c}" id="expdate">
                <apex:actionSupport event="onchange" reRender="numberOfDaysCalc"/>
            </apex:inputField>
        </apex:pageBlockSectionItem>

        <apex:pageBlockSectionItem >
            <apex:outputLabel value="OR" for="or"/>
            <apex:outputText value="" id="or"/>
        </apex:pageBlockSectionItem>

        <apex:pageBlockSectionItem >
            <apex:outputLabel value="Number of Days" for="days"/>
            <apex:inputText value="{!test1obj.MyNumber__c}" id="days">
                <apex:actionSupport event="onkeyup" reRender="expirationDateCalc"/>
            </apex:inputText>
        </apex:pageBlockSectionItem>
    </apex:pageBlockSection>

    <!-- Expiration date calculation -->
    <apex:outputPanel id="expirationDateCalc">
        <apex:variable value="{!TODAY() + test1obj.MyNumber__c}" var="newDate" />           
        <apex:outputText value="{!newDate}" id="dateTxt" style="display:none;"/>
        <script>
            if(jQuery('[id$=dateTxt]').text() != ''){
                var unformattedDate = jQuery('[id$=dateTxt]').text();                
                var parsedDate = Date.parse(unformattedDate);
                var locateDate = (new Date(parsedDate)).toLocaleDateString();
                jQuery('[id$=expdate]').val(locateDate).blur();
            }
        </script>
    </apex:outputPanel>

    <!-- Days until expiration calculation -->
    <apex:outputPanel id="numberOfDaysCalc">
        <apex:variable value="{!IF(NOT(ISBLANK(test1obj.MyDate__c)), IF(TODAY() > test1obj.MyDate__c, TODAY() - test1obj.MyDate__c, test1obj.MyDate__c - TODAY()), 0) }" var="newNumber" />
        <script>
            jQuery('[id$=days]').val('{!newNumber}');
        </script>
    </apex:outputPanel>

</apex:pageBlock>
1
  • This is pretty slick. Still need to use some additional JS to prevent defaults and handle a few edge cases, but overall, pretty cool. Thanks Aug 28, 2014 at 18:17
1

I'm not sure if my implementation fits your requirements... Please let me know.

Simple Javascript solution

In my jsfiddle example I've implemented a short javascript based on jQuery and MomentJs. (Moment JS is a lib to format / parse dates in JS).

The implementation was written in CoffeeScript. Here is the uncompiled code:

updateField_b = (event) ->
    inputNumber = $(event.target).val() // get value of field a
    output = moment().add(inputNumber, "days") // add days to "todays"
    $("#b").val output.format("YYYY-MM-DD") // format and return date

updateField_a = (event) ->
    inputDate = $(event.target).val() // get value from b
    inputMoment = moment(inputDate, "YYYY-MM-DD") // format input
    today = moment(moment().format("YYYY-MM-DD"), "YYYY-MM-DD") // get today
    difference = inputMoment.diff(today) // difference between input - today
    differenceFormatted = moment.duration(difference) // format time between input and today
    $("#a").val differenceFormatted.get("days")

addListener = ->
    $("#a").on "change", (e) ->
        updateField_b e

    $("#b").on "change", (e) ->
        updateField_a e


$(document).ready ->
    console.log("abc")
    $("#a").val(0)
    $("#b").val(moment().format("YYYY-MM-DD"))
    addListener()

JS Fiddle

http://jsfiddle.net/tv916png/

AngularJS

Like in this example: http://jsfiddle.net/YUza7/2/

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .