Country specific phone number validation is broken

If you set a field type to be phone number and select Australia for default country, people will usually put their mobile phone number starting with 04 and the following 8 digits. The form builder however doesn’t like a leading zero and only wants to accept 9 digits so the user will type the leading zero and by 7th digit they will use up the 9 accepted digits so most of the phone numbers stored in data base are missing the last digit.

The phone number validation should either immediately remove the leading zero as it is entered or accept either 10 or 9 digits (10 digits if there is a leading zero and 9 digits if there isn’t) and at the time of saving to database remove the leading zero.

Welcome to the Community, @user21855 :waving_hand:

The 0 at the start of an Australian mobile number (e.g. 0412 345 678) is a “trunk prefix” — it just tells the phone network “this is a domestic call.”

The +61 country code already does that job for international formatting, so it replaces the 0 rather than sitting alongside it.

So, the feature is working correctly in the widget and you just need to drop the leading zero if the country code is already added. Here is an example: 0412 345 678+61 412 345 678.

Let me know if this clears things up or if you have any questions left :slightly_smiling_face:

Max here is the form:

Try entering the 0412345678 and you will see that the form will stop accepting the number after you enter 7. You can’t enter the last digit unless you entered the number without the leading zero.

Got you, thanks!

Our devs found a solution for this case. Please add this script to the Custom JS field on the Settings tab of your widget’s settings:

const CALLING_CODE = '61';
const TRUNK_PREFIX = '0';

const LOCAL_WITH_TRUNK_LENGTH = 10;
const PHONE_INPUT_SELECTOR = '.es-fields-phone input[type="tel"]';

const digitsOnly = (value) => String(value ?? '').replace(/\D/g, '');

const getNationalDigits = (value) => {
  const digits = digitsOnly(value);
  if (!digits.startsWith(CALLING_CODE)) {
    return null;
  }

  return digits.slice(CALLING_CODE.length);
};

const stripAuTrunkPrefixIfComplete = (value) => {
  const national = getNationalDigits(value);
  if (!national) {
    return null;
  }

  if (!national.startsWith(TRUNK_PREFIX)) {
    return null;
  }

  if (national.length < LOCAL_WITH_TRUNK_LENGTH) {
    return null;
  }

  return `+${CALLING_CODE}${national.slice(TRUNK_PREFIX.length)}`;
};

const getFieldId = (input) => input?.id || null;

const applyNormalized = (input, rawValue) => {
  const normalized = stripAuTrunkPrefixIfComplete(rawValue);
  if (!normalized) {
    return false;
  }

  if (digitsOnly(input.value) === digitsOnly(normalized)) {
    return false;
  }

  const fieldId = getFieldId(input);
  if (!fieldId) {
    return false;
  }

  widget.setFieldValue(fieldId, normalized);
  return true;
};

const valueAfterPaste = (input, pastedText) => {
  const value = input.value ?? '';
  const start = input.selectionStart ?? value.length;
  const end = input.selectionEnd ?? value.length;
  return `${value.slice(0, start)}${pastedText}${value.slice(end)}`;
};

const valueAfterInsert = (input, insertedText) => {
  const value = input.value ?? '';
  const start = input.selectionStart ?? value.length;
  const end = input.selectionEnd ?? value.length;
  return `${value.slice(0, start)}${insertedText}${value.slice(end)}`;
};

util.addListener(PHONE_INPUT_SELECTOR, 'input', (event) => {
  const input = event.target;
  if (!(input instanceof HTMLInputElement)) {
    return;
  }

  applyNormalized(input, input.value);
});

util.addListener(PHONE_INPUT_SELECTOR, 'beforeinput', (event) => {
  const input = event.target;
  if (!(input instanceof HTMLInputElement)) {
    return;
  }

  if (event.inputType !== 'insertText' || !event.data) {
    return;
  }

  if (!/^\d+$/.test(event.data)) {
    return;
  }

  const nextValue = valueAfterInsert(input, event.data);
  const normalized = stripAuTrunkPrefixIfComplete(nextValue);
  if (!normalized) {
    return;
  }

  event.preventDefault();
  applyNormalized(input, nextValue);
});

util.addListener(PHONE_INPUT_SELECTOR, 'paste', (event) => {
  const input = event.target;
  if (!(input instanceof HTMLInputElement)) {
    return;
  }

  const pasted = event.clipboardData?.getData('text') ?? '';
  if (!pasted) {
    return;
  }

  const nextValue = valueAfterPaste(input, pasted);
  if (!stripAuTrunkPrefixIfComplete(nextValue)) {
    return;
  }

  event.preventDefault();
  applyNormalized(input, nextValue);
});

Note: Custom JS scripts don’t run in the widget editor, but will work on the website where the widget is installed :slightly_smiling_face:

Check it out and let me know if it worked :slightly_smiling_face:

That worked, thanks for your help.

Awesome, you’re very welcome :wink: