You are viewing limited content. For full access, please sign in.

Question

Question

Can you change a fields date format using LFForm Object?

asked on March 16 Show version history

I am working on a new Forms process that will be used in multiple countries. There are a few date fields on the form. I would like to change the format of the date fields so when an option on the form is selected for US, it will show the date format as MM/DD/YYYY, and when it is selected for Canada, it will show the date format as DD/MM/YYYY.

For changeFieldSettings I am not seeing this as an option so I thought I would ask here to see if maybe the documentation wasn't up to date or if there is another way to accomplish this.

2 0

Replies

replied on March 19

Hi Blake-

It doesn't answer your exact question but might help. We have standardized on YYYY-MM-DD format for our date fields and that seems to work for users across various regions.

3 0
replied on March 20

I prefer the YYYY-MM-DD format too when I can get away with it.  Honestly, the US insistence on M/D/Y is is less than ideal.

Using YYYY-MM-DD is clear regardless of region or user preferences, and if you use dates in document names, it is alphabetically in chronological order.

2 0
replied on March 19

Hi Blake, this is not supported in the Modern Form.

0 0
replied on March 19

Can this be added to the Feature Request list please?

1 0
replied on March 20

No problem, we’ll treat this as a feature request. And I’ve already shared it with the team.

2 0
replied on March 27 Show version history

Hi Blake! as you say changeFieldSettings does not expose a date format option for DateTime fields, and the documentation isn't outdated; it's simply a feature that hasn't been implemented in the LFForm API yet.

That said, here's a workaround that achieves exactly what you need using only the existing LFForm interfaces.

The approach: Instead of relying on the DateTime field's native picker, you use a Single Line field as the visible input (where the user types the date), and a hidden DateTime field that stores the actual parsed value for the process. JavaScript handles the formatting and validation in between.

How it behaves at runtime:

  • When the user selects US, the visible field shows the label Date (MM/DD/YYYY) and formats input accordingly.
  • When the user selects Canada, it switches to Date (DD/MM/YYYY).
  • As the user types digits, slashes are inserted automatically (e.g. typing 01152025 renders as 01/15/2025).
  • Once all 8 digits are entered, the script validates the date (including edge cases like Feb 30) and writes the ISO value YYYY-MM-DD into the hidden DateTime field.
  • A confirmation message (✔ Valid date: 15 Jan 2025) or a warning (⚠ Invalid date) appears below the field in real time.
  • Submission is blocked if no valid date has been stored.

 

Fields needed on your form:

Country selector (Dropdown), Variable name: Country

Visible date input (Single Line), Variable name: Date_Display

Data storage (DateTime, hidden by JS), Variable name: Date_Field

The country field values must match exactly "US" and "Canada" in the script, or you can update the string comparisons to match whatever values you're using. Adding more countries is just a matter of adding else if blocks to two functions.

Hope this helps! It would definitely be great to see native date format control added to changeFieldSettings in a future release, worth submitting as a product idea if you haven't already.

Here is the code: 

// ================================================================
// SOLUTION OVERVIEW: 
// ================================================================
//   1. Hide the actual DateTime field (used only for data storage).
//   2. Show a Single Line field where the user types the date.
//   3. As the user types, auto-insert "/" separators in real time.
//   4. Once 8 digits are entered, parse the date according to the
//      country selected (US = MM/DD/YYYY, Canada = DD/MM/YYYY).
//   5. If valid, write the ISO date (YYYY-MM-DD) into the hidden
//      DateTime field and show a confirmation message.
//   6. Block form submission if no valid date has been stored.
//
// FORM FIELDS REQUIRED:
//   - Country selector  → Dropdown or Radio  → variableName: "Country"
//                         Values must be exactly "US" and "Canada"
//   - Visible date      → Single Line        → variableName: "Date_Display"
//   - Hidden date store → DateTime           → variableName: "Date_Field"
//
// To add more countries, extend the parseDate() and
// updatePlaceholder() functions with additional else-if blocks.
// ================================================================


// ================================================================
// SECTION 1 — FIELD REFERENCES
// Centralized config so IDs/names are easy to update in one place.
// ================================================================
const FIELD = {
  country:     { variableName: "Country" },      // Country selector field
  dateDisplay: { variableName: "Date_Display" }, // Single Line shown to user
  dateHidden:  { variableName: "Date_Field" },   // DateTime field (hidden)
};


// ================================================================
// SECTION 2 — INITIALIZATION
// Runs once when the form loads.
// ================================================================

// Hide the real DateTime field — users should never interact with it directly.
LFForm.hideFields(FIELD.dateHidden);

// Read the current country value (useful if form reloads with a saved draft)
// and set the correct placeholder/label right away.
updatePlaceholder(LFForm.getFieldValues(FIELD.country));


// ================================================================
// SECTION 3 — COUNTRY CHANGE HANDLER
// Fires whenever the user changes the country selection.
// Updates the visible label/placeholder and clears both date fields
// to avoid storing a date interpreted under the wrong format.
// ================================================================
LFForm.onFieldChange(function () {

  const country = LFForm.getFieldValues(FIELD.country);

  // Update the label, placeholder, and subtext of the visible field
  updatePlaceholder(country);

  // Clear the visible input so the user re-enters the date
  LFForm.setFieldValues(FIELD.dateDisplay, "");

  // Clear the stored ISO date in the hidden DateTime field
  LFForm.setFieldValues(FIELD.dateHidden, { dateStr: "" });

}, FIELD.country);


// ================================================================
// SECTION 4 — DATE INPUT HANDLER
// Fires on every keystroke in the visible Single Line date field.
// Handles auto-formatting and real-time validation.
// ================================================================
LFForm.onFieldChange(function () {

  const country  = LFForm.getFieldValues(FIELD.country);
  const rawInput = LFForm.getFieldValues(FIELD.dateDisplay) || "";
  const trimmed  = rawInput.trim();

  // Do nothing if the field is empty
  if (!trimmed) return;

  // Strip everything except digits for processing
  const digitsOnly = trimmed.replace(/\D/g, "");

  // Auto-format: insert "/" separators as the user types
  const formatted = autoFormat(digitsOnly);

  // Only update the field if the formatted string differs from what's
  // already there — prevents an infinite re-render loop
  if (formatted !== trimmed) {
    LFForm.setFieldValues(FIELD.dateDisplay, formatted);
  }

  // Only attempt to parse once the user has entered all 8 digits
  if (digitsOnly.length === 8) {

    const isoDate = parseDate(digitsOnly, country);

    if (isoDate) {
      // Valid date — store it in the hidden DateTime field
      LFForm.setFieldValues(FIELD.dateHidden, { dateStr: isoDate });

      // Show a confirmation message below the field
      LFForm.changeFieldSettings(FIELD.dateDisplay, {
        subtext:    "✔ Valid date: " + toReadable(isoDate),
        CSSClasses: "date-valid"
      });

    } else {
      // Invalid date — clear the hidden field and warn the user
      LFForm.setFieldValues(FIELD.dateHidden, { dateStr: "" });

      LFForm.changeFieldSettings(FIELD.dateDisplay, {
        subtext:    "⚠ Invalid date. Please check the format.",
        CSSClasses: "date-invalid"
      });
    }

  } else {
    // User is still typing — clear any previous status message
    LFForm.changeFieldSettings(FIELD.dateDisplay, {
      subtext:    "",
      CSSClasses: ""
    });
  }

}, FIELD.dateDisplay);


// ================================================================
// SECTION 5 — FORM SUBMISSION GUARD
// Blocks submission if no valid ISO date has been saved yet.
// ================================================================
LFForm.onFormSubmission(function () {

  const storedDate = LFForm.getFieldValues(FIELD.dateHidden);

  if (!storedDate) {
    return { error: "Please enter a valid date before submitting." };
  }

});


// ================================================================
// HELPER FUNCTIONS
// ================================================================

/**
 * autoFormat(digits)
 *
 * Inserts "/" separators into a string of digits as the user types,
 * producing the visual pattern XX/XX/XXXX.
 *
 * The visual separator pattern is the same for both US and Canada —
 * the difference in those locales is purely in how the segments are
 * *interpreted* (MM/DD vs DD/MM), which is handled in parseDate().
 *
 * Examples:
 *   "01"       → "01"
 *   "0115"     → "01/15"
 *   "01152025" → "01/15/2025"
 *
 * @param  {string} digits - Raw digit string (no separators), max 8 chars
 * @returns {string} Formatted string with "/" separators inserted
 */
function autoFormat(digits) {
  // Cap at 8 digits to prevent over-entry
  const d = digits.substring(0, 8);

  if (d.length <= 2) return d;
  if (d.length <= 4) return d.substring(0, 2) + "/" + d.substring(2);

  return d.substring(0, 2) + "/" + d.substring(2, 4) + "/" + d.substring(4);
}


/**
 * parseDate(digits, country)
 *
 * Interprets exactly 8 digits as a date according to the country's
 * format convention, then validates the result using JavaScript's
 * native Date object (which catches edge cases like Feb 30, etc.).
 *
 * Format by country:
 *   "US"     → MM DD YYYY  (positions 0-1 = month, 2-3 = day)
 *   "Canada" → DD MM YYYY  (positions 0-1 = day,   2-3 = month)
 *
 * @param  {string} digits  - Exactly 8 digits, e.g. "01152025"
 * @param  {string} country - Country value from the form selector
 * @returns {string|null} ISO date string "YYYY-MM-DD", or null if invalid
 */
function parseDate(digits, country) {
  if (!digits || digits.length !== 8) return null;

  let day, month, year;

  if (country === "US") {
    // US format: MM/DD/YYYY
    month = parseInt(digits.substring(0, 2), 10);
    day   = parseInt(digits.substring(2, 4), 10);
    year  = parseInt(digits.substring(4, 8), 10);
  } else {
    // Canada (and most other countries): DD/MM/YYYY
    day   = parseInt(digits.substring(0, 2), 10);
    month = parseInt(digits.substring(2, 4), 10);
    year  = parseInt(digits.substring(4, 8), 10);
  }

  // Quick range check before constructing a Date object
  if (month < 1 || month > 12)   return null;
  if (day   < 1 || day   > 31)   return null;
  if (year  < 1900 || year > 2100) return null;

  // Use Date to catch invalid combinations like Feb 30, Apr 31, etc.
  // Note: months in JS Date are 0-indexed, so subtract 1
  const dateObj = new Date(year, month - 1, day);

  const isValid =
    dateObj.getFullYear() === year  &&
    dateObj.getMonth()    === month - 1 &&
    dateObj.getDate()     === day;

  if (!isValid) return null;

  // Return the ISO format required by LFForm.setFieldValues for DateTime fields
  const mm = String(month).padStart(2, "0");
  const dd = String(day).padStart(2, "0");
  return `${year}-${mm}-${dd}`;
}


/**
 * toReadable(isoDate)
 *
 * Converts an ISO date string (YYYY-MM-DD) into a short human-readable
 * format used in the confirmation subtext, e.g. "15 Jan 2025".
 *
 * @param  {string} isoDate - Date in "YYYY-MM-DD" format
 * @returns {string} Human-readable date string
 */
function toReadable(isoDate) {
  const [y, m, d] = isoDate.split("-");
  const months = [
    "Jan","Feb","Mar","Apr","May","Jun",
    "Jul","Aug","Sep","Oct","Nov","Dec"
  ];
  return `${d} ${months[parseInt(m, 10) - 1]} ${y}`;
}


/**
 * updatePlaceholder(country)
 *
 * Updates the label, placeholder text, and subtext of the visible
 * Single Line field to reflect the expected input format for the
 * currently selected country.
 *
 * Extend this function with additional else-if blocks to support
 * more countries or regions.
 *
 * @param {string} country - Country value from the form selector
 */
function updatePlaceholder(country) {
  if (country === "US") {
    LFForm.changeFieldSettings(FIELD.dateDisplay, {
      label:       "Date (MM/DD/YYYY)",
      placeholder: "MM/DD/YYYY",
      subtext:     "Format: month/day/year"
    });
  } else if (country === "Canada") {
    LFForm.changeFieldSettings(FIELD.dateDisplay, {
      label:       "Date (DD/MM/YYYY)",
      placeholder: "DD/MM/YYYY",
      subtext:     "Format: day/month/year"
    });
  } else {
    // No country selected yet — show a neutral prompt
    LFForm.changeFieldSettings(FIELD.dateDisplay, {
      label:       "Date",
      placeholder: "Please select a country first",
      subtext:     ""
    });
  }
}

 

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.