0

I am trying to use the static resource "dateformat" a javascript file containing the following code to auto-format the input of an apex input text field.

When I embed the script directly into the VFP with <script> tags it works, but when I try to include it as a static resource <apex:includeScript value="{!$Resource.dateformat}"/> it does not.

Why?

var date = document.getElementById('page1:form1:searchBlock:searchSection:j_id6:DOB');
console.log('date: ' + date);
function checkValue(str, max) {
  if (str.charAt(0) !== '0' || str == '00') {
    var num = parseInt(str);
    if (isNaN(num) || num <= 0 || num > max) num = 1;
    str = num > parseInt(max.toString().charAt(0)) && num.toString().length == 1 ? '0' + num : num.toString();
  };
  return str;
};

date.addEventListener('input', function(e) {
  this.type = 'text';
  var input = this.value;
  if (/\D\/$/.test(input)) input = input.substr(0, input.length - 3);
  var values = input.split('/').map(function(v) {
    return v.replace(/\D/g, '')
  });
  if (values[0]) values[0] = checkValue(values[0], 12);
  if (values[1]) values[1] = checkValue(values[1], 31);
  var output = values.map(function(v, i) {
    return v.length == 2 && i < 2 ? v + '/' : v;
  });
  this.value = output.join('').substr(0, 14);
});

date.addEventListener('blur', function(e) {
  this.type = 'text';
  var input = this.value;
  var values = input.split('/').map(function(v, i) {
    return v.replace(/\D/g, '')
  });
  var output = '';

  if (values.length == 3) {
    var year = values[2].length !== 4 ? parseInt(values[2]) + 2000 : parseInt(values[2]);
    var month = parseInt(values[0]) - 1;
    var day = parseInt(values[1]);
    var d = new Date(year, month, day);
    if (!isNaN(d)) {
      document.getElementById('result').innerText = d.toString();
      var dates = [d.getMonth() + 1, d.getDate(), d.getFullYear()];
      output = dates.map(function(v) {
        v = v.toString();
        return v.length == 1 ? '0' + v : v;
      }).join(' / ');
    };
  };
  this.value = output;
});

EDIT:

I also tried adding IDs to each apex element and getting the elementId of the inputText that way: {!$Component.page.form.pgBlk.pgBlkSec.pgBlkSecItem.txtName}, but the date var is still null.

<apex:page id="page">
    <apex:form id="form">
        <apex:pageBlock id="pgBlk">
            <apex:pageBlockSection id="pgBlkSec">
                <apex:pageBlockSectionItem id="pgBlkSecItem">
                    <apex:inputText id="txtName" />
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
9
  • 1
    Do you get any error messages?
    – Adrian Larson
    Commented Apr 23, 2018 at 16:46
  • No I don't. I checked the console log to see if the date variable outputs and it does not...
    – S.B.
    Commented Apr 23, 2018 at 17:00
  • Have you added any debugs? Does setting window.onload= even work?
    – Adrian Larson
    Commented Apr 23, 2018 at 17:08
  • 1
    Step 1: Check if the library gets loaded at all. Network tab of the developer console
    – stwissel
    Commented Apr 23, 2018 at 17:11
  • @AdrianLarson I removed the onload and I am seeing my console log from line 2 but the date variable is undefined. I'm assuming the JS file doesn't know where to look for "page1:form1:searchBlock:searchSection:j_id6:DOB"? Maybe a naming issue?
    – S.B.
    Commented Apr 23, 2018 at 17:16

1 Answer 1

1

The challenge most likely is the ID you are using. There is NO guarantee that this ID won't change (popular challenge in other server side renderings like JSF too).

Suggest you add a styleClass="dateField" attribute to the element and then use document.getElementsByClassName("dateField")[0] to access it.

You could try to add an attribute html-type="date" and see if it turns it into a HTML5 date control (or just throws an error).

When your backing field is a date type, use showDatePicker as attribute

Update

At the time your code is loading the DOM hasn’t rendered the field yet. Best approach (also for maintenance): define the current anonymous listener functions as named functions and don’t try to attach the listeners in your code.

Rather refer to your functions in the event definitions of your inputField markup. This way they are only called when the element is available, can be used by multiple date fields and code doesn’t break when fields are renamed or removed.

Bonus: wrap your functions into a single object to avoid too much “pollution”. Something like:

var dateValidator = {};
 dateValidator.change = function(......){...};

then your markup attribute would be onchange=“dateValidator.change”

4
  • I gave the styleClass attribute a shot, but now the date variables come back undefined instead of null.
    – S.B.
    Commented Apr 23, 2018 at 17:43
  • Long answer short: when you run that code, the DOM hasn’t rendered the field in question yet. You need to “wait” until the document is ready. So instead of trying to attach the event listeners in your function, just define them as named functions and refer to them in your inputField markup. Alternative wrap your code in a function that adds an onDocumentReady listener. Important: ADD a listener, don’t overwrite
    – stwissel
    Commented Apr 24, 2018 at 0:57
  • This partially works... upon typing the date into the field the first time and clicking out of the field the typed characters vanish. When you type the date in again, the validation is performed. EDIT: I added an onClick in addition to the onChange and got this working. Weird.
    – S.B.
    Commented Apr 24, 2018 at 20:30
  • Glad it worked out
    – stwissel
    Commented Apr 25, 2018 at 7:26

You must log in to answer this question.

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