How does OOB Phone Number E164 field is being validated?

GV Saranesh Kum
Kilo Guru

Hello Community,

Any idea how does phone number E164 field is being validated? I checked in validation scripts, but no luck.

It's validation is being performed during 'onChange' or 'onLeave' events. But i am not seeing any script doing that.

Any insight is appreciated.

Thank you

Saranesh.

6 REPLIES 6

mamann
Mega Guru

There is an onChange function being ran on the field called onChangePhoneNumberE164()


You can inspect what this function is doing by using Developer Tools in your browser but calling it (in the correct frame) without the parenthesis, then clicking on the returned function name.



See the code for onChangePhoneNumberE164 below which I got directly from my browser dev tools



function g_phoneNumberDependentChange(ref, dependent) {


      element = gel('country_' + ref);


      if (element)


              new PhoneNumberE164(element).changePhoneNumberFromDependent(dependent);


      else


              new PhoneNumberE164(gel('disp_' + ref)).changePhoneNumberFromDependent(dependent);


}




function onChangePhoneNumberE164(type, element) {


      var pn = new PhoneNumberE164(element, (type == 'select'));


      if (type == 'select')


              pn.changePhoneNumberFromSelect();


      else


              pn.changePhoneNumberFromInput();


}


var PhoneNumberE164 = Class.create();


PhoneNumberE164.prototype = {


      element: null,


      phoneElement: null,


      displayElement: null,


      selectElement: null,


      countryTextElement: null,


      ref: null,


      nationalFormat: null,


      strict: null,


      gdc: null,


      ldc: null,


      ldcFollowsGdc: null,


      usersCountry: null,


      allowNationalEntry: null,


      valid: true,


      hasSelect: false,


      isSelect: false,


      displayNationalForUser: false,


      selectedCache: null,


      displayCountryText: null,


      displayCountryNational: null,


      initialize: function(element, isSelect) {


              this.element = element;


              this.isSelect = isSelect;


              this._loadReferenceId();


              this.phoneElement = gel(this.ref);


              this.valid = true;


              this.displayElement = gel("disp_" + this.ref);


              this.selectElement = gel("country_" + this.ref);


              this.countryTextElement = gel("country_txt_" + this.ref);


              this._loadElementData();


      },


      _loadReferenceId: function() {


              this.ref = this.element.getAttribute("element_ref");


      },


      _loadElementData: function() {


              this.nationalFormat = (this.displayElement.getAttribute("data-national") == 'true');


              this.strict = (this.displayElement.getAttribute("data-strict") == 'true');


              this.gdc = this.displayElement.getAttribute("data-gdc");


              this.ldc = this.displayElement.getAttribute("data-ldc");


              this.ldcFollowsGdc = this.displayElement.getAttribute("data-local-global");


              this.allowNationalEntry = (this.displayElement.getAttribute("data-allow-national") == 'true');


              this.usersCountry = null;


              this.displayNationalForUser = false;


              if (this.displayElement.getAttribute("data-localuser") == 'true') {


                      this.displayNationalForUser = true;


                      this.usersCountry = this.displayElement.getAttribute("data-user-country");


              }


              this.hasSelect = (this.displayElement.getAttribute("data-select") == 'true');


              this.selectedCache = this.displayElement.getAttribute("data-selected-cache");


              this.displayCountryText = this.displayElement.getAttribute("data-country-text");


              this.displayCountryTextNational = (this.displayElement.getAttribute("data-country-text-national") == 'true');


      },


      _ltrim: function(value) {


              if (value == null)


                      return null;


              return value.replace(/^\s+/, '');


      },


      changePhoneNumberFromDependent: function(dependentRef) {


              var phoneNumber = this._ltrim(this.phoneElement.value);


              if (this.isSelect)


                      if (phoneNumber != "")


                              return;


              if (!gel(dependentRef))


                      return;


              this._updateFromDependent(dependentRef);


      },


      updateSelectForUser: function(dependentRef) {


              this._updateFromDependent(dependentRef);


      },


      changePhoneNumberFromInput: function() {


              if (this.element == this.phoneElement)


                      this.displayElement.value = this.phoneElement.value;


              if (this.hasSelect)


                      this._changePhoneNumberFromInputWithSelect();


              else


                      this._changePhoneNumberFromInputNoSelect();


      },


      _changePhoneNumberFromInputWithSelect: function() {


              var phoneNumber = this._ltrim(this.displayElement.value + "");


              var strippedPhoneNumber = this._stripCharacters(phoneNumber);


              if (strippedPhoneNumber == "") {


                      this.phoneElement.value = "";


                      this._setCountryText("");


                      this._validateEntry();


                      return;


              }


              var listElementValue = this.selectElement.value + "";


              var fullCountryProvided = (phoneNumber.substr(0, 1) == "+");


              var gdc = "";


              var ldc = "";


              var ldcFollowsGdc = "";


              if (listElementValue != "") {


                      var vals = listElementValue.split(',');


                      gdc = vals[0];


                      ldc = vals[1];


                      ldcFollowsGdc = (vals[2] == true);


              }


              var partialMatch = "";


              var findFormat = true;


              if (fullCountryProvided) {


                      this._setSelectedCache(strippedPhoneNumber + "," + this.selectElement.value);


                      strippedPhoneNumber = "+" + strippedPhoneNumber;


                      this._setUserNationalFormatFromGDC(this.gdc, strippedPhoneNumber);


                      this.reformatPhoneNumber(strippedPhoneNumber, strippedPhoneNumber);


                      return;


              } else if (this.allowNationalEntry) {


                      if (!ldcFollowsGdc && strippedPhoneNumber.substr(0, ldc.length) == ldc)


                              strippedPhoneNumber = strippedPhoneNumber.substr(ldc.length);


                      strippedPhoneNumber = "+" + gdc + strippedPhoneNumber;


              } else {


                      findFormat = false;


                      partialMatch = "LOCAL";


              }


              if (findFormat) {


                      this._setSelectedCache(strippedPhoneNumber + "," + this.selectElement.value);


                      this._setUserNationalFormat();


                      this.reformatPhoneNumber(strippedPhoneNumber, strippedPhoneNumber);


              } else {


                      this._setSelectedCache(phoneNumber + "," + this.selectElement.value);


                      this.phoneElement.value = phoneNumber;


                      this._setCountryText("");


                      this._invalidateEntry();


              }


      },


      _changePhoneNumberFromInputNoSelect: function() {


              var phoneNumber = this._ltrim(this.displayElement.value + "");


              this._setSelectedCache(phoneNumber + "," + this.gdc + "," + this.ldc + "," + this.ldcFollowsGdc);


              var strippedPhoneNumber = this._stripCharacters(phoneNumber);


              if (strippedPhoneNumber == "") {


                      this.phoneElement.value = "";


                      this._setCountryText("");


                      this._validateEntry();


                      return;


              }


              this._setUserNationalFormatFromGDC(this.gdc, phoneNumber);


              var findFormat = true;


              if (phoneNumber.substr(0, 1) == "+") {


                      strippedPhoneNumber = "+" + strippedPhoneNumber;


                      cleanNumber = strippedPhoneNumber;


              } else if (!this.allowNationalEntry)


                      findFormat = false;


              else {


                      cleanNumber = strippedPhoneNumber;


                      strippedPhoneNumber = "+" + this.gdc + strippedPhoneNumber;


              }


              if (findFormat) {


                      this.reformatPhoneNumber(strippedPhoneNumber, cleanNumber);


              } else {


                      this.phoneElement.value = phoneNumber;


                      this._setCountryText("");


                      this._invalidateEntry();


              }


      },


      changePhoneNumberFromSelect: function() {


              this._setUserNationalFormat();


              this._validateEntry();


              var phoneNumber = this.rebuildPhoneNumberFromSelect();


              if (phoneNumber == "")


                      return;


              this.reformatPhoneNumber(phoneNumber, phoneNumber);


      },


      _setUserNationalFormat: function() {


              if (!this.displayNationalForUser)


                      return false;


              if (this.usersCountry != null) {


                      var listCountry = this.selectElement.options[this.selectElement.selectedIndex].text;


                      if (listCountry == this.usersCountry) {


                              this._setDisplayLocal()


                              this.nationalFormat = true;


                      } else {


                              this._setDisplayGlobal();


                              this.nationalFormat = false;


                      }


              }


              return this.nationalFormat;


      },


      _setUserNationalFormatFromGDC: function(gdc, phoneNumber) {


              if (!this.nationalFormat && !this.displayNationalForUser)


                      return false;


              if (this.displayNationalForUser) {


                      var strippedPhoneNumber = this._stripCharacters(phoneNumber);


                      if (phoneNumber.substr(0, 1) == "+") {


                              if (strippedPhoneNumber.substr(0, gdc.length) == gdc) {


                                      this.nationalFormat = true;


                              } else {


                                      this.nationalFormat = false;


                              }


                      } else


                              this.nationalFormat = true;


              }


              return this.nationalFormat;


      },


      rebuildPhoneNumberFromSelect: function() {


              var listElementValue = this.selectElement.value + "";


              var phoneNumber = this.displayElement.value + "";


              var fromGDC = "";


              var fromLDC = "";


              var fromLDCFollowsGDC = true;


              var toGDC = "";


              var toLDC = "";


              var toLDCFollowsGDC = true;


              if (this.selectedCache != "") {


                      var from = this.selectedCache.split(",");


                      phoneNumber = from[0];


                      if (from.length > 1) {


                              fromGDC = from[1];


                              fromLDC = from[2];


                              fromLDCFollowsGDC = (from[3] == 'true');


                      }


              }


              if (listElementValue != "") {


                      var to = listElementValue.split(",");


                      toGDC = to[0];


                      toLDC = to[1];


                      toLDCFollowsGDC = (to[2] == 'true');


              }


              var strippedPhoneNumber = this._stripCharacters(phoneNumber);


              var gdcFound = false;


              if (fromGDC && strippedPhoneNumber.substr(0, fromGDC.length) == fromGDC) {


                      strippedPhoneNumber = strippedPhoneNumber.substr(fromGDC.length);


                      gdcFound = true;


              }


              if (fromLDC && strippedPhoneNumber.substr(0, fromLDC.length) == fromLDC)


                      if (!gdcFound || fromLDCFollowsGDC)


                              strippedPhoneNumber = strippedPhoneNumber.substr(fromLDC.length);


              if (strippedPhoneNumber == "")


                      return "";


              var phoneNumber = "+" + toGDC;


              if (toLDCFollowsGDC)


                      if (strippedPhoneNumber.substr(0, toLDC.length) != toLDC)


                              phoneNumber += toLDC;


              phoneNumber += strippedPhoneNumber;


              return phoneNumber;


      },


      _getCountryLocation: function(phoneNumber) {


              var listElementOptions = this.selectElement.options;


              var countryLocation = -1;


              for (var i = 0; listElementOptions.length > i; i++) {


                      var option = listElementOptions[i];


                      if (option.value == "")


                              continue;


                      var optionGDC = option.value.split(",")[0];


                      if (phoneNumber.substr(0, optionGDC.length) == optionGDC) {


                              countryLocation = i;


                              break;


                      }


              }


              return countryLocation;


      },


      _selectCountryOption: function(optionPosition) {


              if (optionPosition < 0) {


                      if (this.strict)


                              this._invalidateEntry();


                      else {


                              var listElementOptions = this.selectElement.options;


                              var countryLocation = -1;


                              var found = false;


                              for (var i = 0; listElementOptions.length > i; i++) {


                                      var option = listElementOptions[i];


                                      if (option.value == "") {


                                              option.selected = true;


                                              found = true;


                                              break;


                                      }


                              }


                              if (!found)


                                      this._invalidateEntry();


                      }


              } else


                      this.selectElement.options[optionPosition].selected = true;


              if (this.usersCountry != null) {


                      var country = this.selectElement.options[this.selectElement.selectedIndex].text;


                      if (country == this.usersCountry)


                              this._setDisplayLocal();


                      else


                              this._setDisplayGlobal();


              }


      },


      _setToUsersCountry: function() {


              var listElementOptions = this.selectElement.options;


              if (this.usersCountry != null)


                      for (var i = 0; listElementOptions.length > i; i++) {


                              var option = listElementOptions[i];


                              if (option.text == this.usersCountry) {


                                      option.selected = true;


                                      return;


                              }


                      }


      },


      reformatPhoneNumber: function(phoneNumber, cleanPhoneNumber) {


              if (phoneNumber && phoneNumber == "")


                      return;


              if (cleanPhoneNumber.substr(0, 1) != "+" && phoneNumber.substr(0, 1) == "+")


                      this.phoneElement.value = phoneNumber;


              else


                      this.phoneElement.value = cleanPhoneNumber;


              var ajax = new GlideAjax('PhoneNumberFormatter');


              ajax.addParam('sysparm_local', this.nationalFormat);


              ajax.addParam('sysparm_phoneNumber', phoneNumber);


              ajax.addParam('sysparm_strict', this.strict);


              ajax.addParam('sysparm_showText', (this.countryTextElement != null));


              ajax.getXML(this.reformatPhoneNumberResponse.bind(this), null, cleanPhoneNumber);


              this._invalidateEntry();


      },


      reformatPhoneNumberResponse: function(response, cleanPhoneNumber) {


              var answers = response.responseXML.documentElement.getAttribute("answer").split(",");


              var phoneNumber = unescape(answers[0]);


              var countryText = null;


              var newOptionValue = null;


              if (answers.length > 1)


                      countryText = unescape(answers[1]);


              if (answers.length > 2)


                      newOptionValue = unescape(answers[2]);


              this._setCountryText(countryText);


              this._setNewOptionText(countryText, newOptionValue);


              if (phoneNumber == "NO_MATCH" || phoneNumber == "") {


                      if (cleanPhoneNumber != null) {


                              var localizedNumber = cleanPhoneNumber;


                              if (this.selectElement && this.selectElement.value != "" && this.nationalFormat && localizedNumber.substr(0, 1) == '+') {


                                      var gdc = this.selectElement.value.split(',')[0];


                                      var ldc = this.selectElement.value.split(',')[1];


                                      if (localizedNumber.substr(1, gdc.length) == gdc) {


                                              localizedNumber = localizedNumber.substr(gdc.length + 1);


                                              localizedNumber = ldc + localizedNumber;


                                      }


                              }


                              this.displayElement.value = localizedNumber;


                              if (localizedNumber.startsWith("+"))


                                      this._setCountryText("");


                      }


                      this._invalidateEntry();


                      return;


              }


              this.displayElement.value = phoneNumber;


              this._validateEntry();


      },


      _updateFromDependent: function(dependentRef) {


              var ajax = new GlideAjax('PhoneNumberDependent');


              if (dependentRef && dependentRef.length > 0)


                      ajax.addParam('sysparm_sys_id', gel(dependentRef).value);


              else


                      ajax.addParam('sysparm_sys_id', "");


              ajax.getXML(this.updateFromDependentResponse.bind(this));


      },


      updateFromDependentResponse: function(response) {


              var answers = response.responseXML.documentElement.getAttribute("answer").split(",");


              var countryText = unescape(answers[0]);


              var newOptionValue = null;


              if (answers.length > 1)


                      newOptionValue = unescape(answers[1]);


              this._setNewOptionText(countryText, newOptionValue);


              if (!this.isSelect) {


                      var locators = newOptionValue.split(",");


                      if (locators.length >= 3) {


                              this._setSelectedCache(this.displayElement.value + "," + locators[0] + "," + locators[1] + "," + locators[2]);


                              this._setUserNationalFormatFromGDC(locators[0], "");


                              this.gdc = locators[0];


                              this.ldc = locators[1];


                              this.ldcFollowsGdc = locators[2];


                              this.displayElement.setAttribute("data-gdc", locators[0] + "");


                              this.displayElement.setAttribute("data-ldc", locators[1] + "");


                              this.displayElement.setAttribute("data-local-global", locators[2] + "");


                              this.displayElement.value = this.phoneElement.value;


                              this._changePhoneNumberFromInputNoSelect()


                      }


              }


      },


      _setCountryText: function(countryText) {


              if (this.countryTextElement != null) {


                      if (!this.displayCountryTextNational) {


                              if ((this.displayCountryText == 'true' || this.displayCountryText == 'all') && countryText != null && countryText != 'null')


                                      this.countryTextElement.innerHTML = countryText;


                              else


                                      this.countryTextElement.innerHTML = "";


                      } else if (countryText != null && countryText != 'null') {


                              if (this.displayNationalForUser && countryText == this.usersCountry)


                                      this.countryTextElement.innerHTML = countryText;


                              else if (!this.displayNationalForUser)


                                      this.countryTextElement.innerHTML = countryText;


                              else


                                      this.countryTextElement.innerHTML = "";


                      } else


                              this.countryTextElement.innerHTML = "";


              }


      },


      _setNewOptionText: function(territoryText, value) {


              if (!territoryText || !value || !this.selectElement)


                      return;


              var listElementOptions = this.selectElement.options;


              var newOption = cel('option');


              newOption.text = territoryText;


              newOption.value = value;


              var countryLocation = -1;


              for (var i = 0; listElementOptions.length > i; i++) {


                      if (listElementOptions[i].text == territoryText) {


                              countryLocation = i;


                              break;


                      }


              }


              if (countryLocation >= 0) {


                      this.selectElement.options[countryLocation].selected = true;


                      return;


              }


              var countryLocation = -1;


              var found = false;


              for (var i = 0; listElementOptions.length > i; i++) {


                      countryLocation = i;


                      if (listElementOptions[i].text > territoryText ||


                              listElementOptions[i].text == "Other / Unknown"


                      ) {


                              found = true;


                              break;


                      }


              }


              if (!found)


                      countryLocation = listElementOptions.length;


              var saved = [];


              var i;


              for (i = 0; i < this.selectElement.options.length; i++)


                      saved.push(this.selectElement.options[i]);


              this.selectElement.options.length = 0;


              for (i = 0; i < countryLocation; i++)


                      this.selectElement.options[this.selectElement.options.length] = saved[i];


              this.selectElement.options[this.selectElement.options.length] = newOption;


              while (i < saved.length)


                      this.selectElement.options[this.selectElement.options.length] = saved[i++];


              this.selectElement.options[countryLocation].selected = true;


              var cacheValues = this.selectedCache.split(',');


              var strippedPhoneNumber = cacheValues[0];


              this._setSelectedCache(strippedPhoneNumber + "," + this.selectElement.value);


      },


      _stripCharacters: function(phoneNumber) {


              return phoneNumber.replace(/\D/g, '');


      },


      _setDisplayLocal: function() {


              this.displayElement.setAttribute("data-national", "true");


      },


      _setDisplayGlobal: function() {


              this.displayElement.setAttribute("data-national", "false");


      },


      _invalidateEntry: function() {


              if (this.strict)


                      this.displayElement.className = "ref_invalid";


              else


                      this.displayElement.className = "ref_dynamic";


              this.displayElement.setAttribute("data-valid", "false");


              this.valid = false;


              if (document.documentElement.getAttribute('data-doctype') == 'true') {


                      this.displayElement.className += " form-control";


              }


      },


      _validateEntry: function() {


              this.displayElement.className = "";


              this.displayElement.setAttribute("data-valid", "true");


              this.valid = true;


              if (document.documentElement.getAttribute('data-doctype') == 'true') {


                      this.displayElement.className = "form-control";


              }


      },


      _setSelectedCache: function(value) {


              this.displayElement.setAttribute("data-selected-cache", value);


              this.selectedCache = value;


      },


      type: 'PhoneNumberE164'


}


Thanks Mark. I see it now.


I believe we cannot modify this code as per business requirements. Please confirm.



1. Business looks to modify the alert message content.


2. users filling the field and hitting submit button directly, throws a prompt. This should be addressed by creating On-Submit event i guess.


We don't have direct access to this code, so the only way to modify it would be to override it, but that's not usually recommended.


You could write an onLoad client script (or perhaps a UI Policy) and paste the above code in there, then make your modifications.


The only thing I'm not sure of (or if it can be controlled) is the order in which SN's version would load and when your version would load. If using a UI policy you could give it a very high order number.



What are you trying to change with it? If something is broken I would suggesting also opening a HI ticket with Service Now


Thanks Mark.



The OOB script written is for On-Change Event. In our scenario, On-change event is getting bypassed and On-submit event is created directly, where the script throws error as it dint get chance to re-format it and considering it as wrong value.



I will try to incorporate this in On-submit client script and see if the desired is possible.



Thanks again for the insight. Much appreciated.