Skip to Main Content

Java Development Tools

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

ADF Faces Masked Input

Dimitar DimitrovOct 26 2023 — edited Oct 26 2023

A customer of ours asked us to implement masked input on some input fields in their ADF Faces 12.2.1.4 application. We were able to do it successfuly. As far as there were some problems while trying to implement it, I would like to share info about how we were able to workaround them.

We are using Josh Bush's Masked Input Plugin for jQuery for the job:
https://github.com/digitalBush/jquery.maskedinput/blob/master/dist/jquery.maskedinput.js

Our approach is to attach a client listener on the “focus” event to the <af:inputText> component, in order to set masked input on the corresponding HTML <input> when the field gets the focus:

<af:document title="Masked Input" id="d1">
  <f:facet name="metaContainer">
    <af:resource type="javascript"
        source="/resources/javaScript/jquery-3.5.1.slim.min.js"/>
    <af:resource type="javascript"    
        source="/resources/javaScript/jquery.maskedinput.js"/>
    <af:resource type="javascript">

function maskedInput(focusEvent) {
 var component = focusEvent.getSource();
 var inputMask = component.getProperty("inputMask");
 if (inputMask!=null) {
   // Get the native HTML input element
   var nativeElement = focusEvent.getNativeEventTarget();
   if (nativeElement!=null) {
     // Set masked input
     jQuery(nativeElement).mask(inputMask, {autoclear:false});
   }
 }
}
    </af:resource>
  </f:facet>  

...

  <af:inputText label="Phone number" value="#{viewScope.myPhone}" autoSubmit="true">
    <af:clientListener method="maskedInput" type="focus"/>
    <af:clientAttribute name="inputMask" value="(999) 999-999"/>
  </af:inputText>
  

It seemed to work, but when the input field is configured with autoSubmit="true", a problem occurs:
When the user enters the empty field, the mask will show. If the user just exits the field (without entering anything in it), autoSubmit="true" will cause the empty mask to be submitted as a value before the plugin is able to clear the mask on blur.

We solved this problem by adding a “valueChange” client listener to the field in order to catch the submitted value and replace it to an empty string if it is equal to the input mask:

/**
 * Sets masked input on an &lt;af:inputText> component.
 * The function should be attached to &lt;af:inputText> components as
 * a "focus" client listener. The input mask should be set to the input component
 * as an &lt;af:clientAttribute name="inputMask" ...>
 * 
 * Requires jquery.maskedinput.js
 */
function maskedInput(focusEvent) {
  var component = focusEvent.getSource();
  var inputMask = component.getProperty("inputMask");
  if (inputMask!=null) {
    var nativeElement = focusEvent.getNativeEventTarget();
    if (nativeElement!=null) {
      // Set masked input
      jQuery(nativeElement).mask(inputMask, {autoclear:false});
      
      // Prevent the mask from causing unwanted valueChange
      if (component.getProperty("clientListeners").valueChange==null) {
        component.addEventListener("valueChange",
          function(event) {
            // Replace wildcard characters in the mask with "_"
            var visibleMask = inputMask.replace(/[9a*]/g, '_').replace(/\?/g, '');

            if (event.getNewValue() === visibleMask) {
              event.cancel();
              if (event.getOldValue()!=null) {
                component.setValue("");
              }
            }
          });
      }
    }
  }
}

...

<af:inputText label="Phone number" value="#{viewScope.myPhone}" autoSubmit="true"> 
  <af:clientListener method="maskedInput" type="focus"/> 
  <af:clientAttribute name="inputMask" value="(999) 999-999"/> 
</af:inputText>

If the input field has an attached JSF validator, the valudator will fire at JSF Validarion phase before the valueChange event (i.e. before our valueChange listener has any chance to catch and suppress the wrong value):

<af:inputText label="Phone number" value="#{viewScope.myPhone}" autoSubmit="true">
  <af:validateRegExp pattern="\(\d\d\d\) \d\d\d-\d\d\d"
                     messageDetailNoMatch="Invalid phone number {1}"/>
  <af:clientListener method="maskedInput" type="focus"/>
  <af:clientAttribute name="inputMask" value="(999) 999-999"/>
</af:inputText>

You can workaround this problem by changing the RegEx validator in order to treat the empty mask as a valid value. Thus it will not fire an error and our “valueChange” listener will be executed and it will suppress the wrong value:

<af:inputText label="Phone number" value="#{viewScope.myPhone}" autoSubmit="true">
  <af:validateRegExp pattern="\(\d\d\d\) \d\d\d-\d\d\d|\(___\) ___-___"
                     messageDetailNoMatch="Invalid phone number {1}"/>
  <af:clientListener method="maskedInput" type="focus"/>
  <af:clientAttribute name="inputMask" value="(999) 999-999"/>
</af:inputText>

I hope this will help others when implementing masked input in their ADF applications.

Thanks.

Comments
Post Details
Added on Oct 26 2023
4 comments
644 views