Using input masks with a jQuery plugin

Ever wondered why the Rich Faces (RF) library does not support a control that can handle input masks for numeric and other special type fields ?

Well, they did not need to. The RF team has integrated jQuery, the popular Javascript library which has a rich set of plugins to help you with this.

 

Some links for jQuery

http://jquery.com/

http://plugins.jquery.com/

 

 

RF jQuery example

http://livedemo.exadel.com/richfaces-demo/richfaces/jQuery.jsf?c=jQuery&tab=usage

 

If you are not using jQuery already, I encourage you to take a look at it. I was up and running in less than a hour when I first started - not because I am smart but because it is that simple

 

 

Now to the subject of my article.

 

I needed a plugin that supported flexible input masks for numeric and text inputs. I found such a plugin at

http://www.meiocodigo.com/projects/meiomask/

 

 

 

Very easy to setup -  all you need to do is set the alt attribute for your component with a unique name. Then initialize the mask plugin for the field with this name. Let's study my working example together.

 

I have a very simple CRUD screen for a table with these fields

carrier_id not null number(38),  -- surrogate key
carrier_code not null varchar2(3), -- unique key
carrier_name not null varchar2(30)

 

My rule for carrier code was that it should be uppercase and alphabetic. I wanted a way to validate it on my model as well on the client side.

For the model, I used a regex pattern -

    @Column(name = "CARRIER_CODE", unique = true, nullable = false, length = 3)
    @NotNull
    @Length(max = 3)
    @Pattern(regex="[A-Z]+", message="Carrier code must be upper case, alphabetic and have no spaces")
    public String getCarrierCode() {
        return this.carrierCode;
    }

 

On the client side, I wanted a like mask for this input and also inform the user if they they typed in invalid characters.

My carrierEdit.xhtml file where everything happens

 

Head section of page

 

    // load jQuery library bundled with RF

    <a4j:loadScript src="resource://jquery.js" />

 

    <!--  for input mask -->
    <script type="text/javascript" src="#{contextPath}/js/jquery/plugins/jquery.meiomask.compressed.js" ></script>

 


    <script type="text/javascript">
    // Use jQuery via jQuery(...)
         jQuery(document).ready(function(){
          
           setMask();   
                      
         });  //end ready funciton

 

        //intiialize meiomask plugin

        function setMask() {
               jQuery('#carrierEditForm\\:carrierCodeDecoration\\:carrierCode').setMask({mask:'ZZZ',
                    onInvalid:function(c,nKey){
                        jQuery('#carrierEditForm\\:codemask_alert').text('You can input only upper case alphabetic characters').css('color','red');
                    },
                    onValid:function(c,nKey){
                        jQuery('#carrierEditForm\\:codemask_alert').text('Code can only consist of alphabets and no spaces').css('color','green');
                    }
                });

 

        }   
   
    </script>

 

Body section of page (only relevant fields)

    <h:form id="carrierEditForm" >
        <rich:panel>
            <f:facet name="header">#{carrierHome.managed ? 'Edit' : 'Add'} carrier</f:facet>
               <s:validateAll>
               
                <f:facet name="afterInvalidField"> <s:message styleClass="message" /></f:facet>
                <f:facet name="aroundInvalidField"><s:span styleClass="errors"/></f:facet>
               
                 <div class="edit" >
                <table width="100%" cellspacing="5" cellpadding="5" >
                  <tr>
                    <th align="right"><h:outputLabel for="carrierCode" value="#{messages.carrier_carrierCode}: "/><s:span styleClass="required">*</s:span></th>
                    <td>
                        <h:outputText value="#{carrierHome.instance.carrierCode}" styleClass="keyfield" rendered="#{carrierHome.managed}" />
                   
                        <s:fragment rendered="#{not carrierHome.managed}">
                            <s:decorate id="carrierCodeDecoration">
                                <a4j:region id="a4jCarrierCodeRegion" >
                                   <h:inputText id="carrierCode"
                                           size="5" maxlength="3"
                                       required="true" label="Carrier code"
                                          alt="carriercodemask"                      
                                       autocomplete="off" styleClass="#{invalid?'errors':''}"
                                      valueChangeListener="#{carrierHome.keyFieldChangeEvent}"
                                          value="#{carrierHome.instance.carrierCode}"  >
   
                                     <a4j:support event="onblur"  ajaxSingle="true" bypassUpdates="true"
                                         reRender="carrierCodeDecoration" action="#{carrierHome.validateCarrierCode}"
                                         oncomplete="setMask()"/>  
                                </h:inputText>
                                </a4j:region>
                            </s:decorate>
                            </s:fragment>
                    </td>
                </tr>

 

                <tr>
                <td></td>
                <td><h:outputText id="codemask_alert"

                              style="color:green;font-size: 1.1em;font-style:italic;"

                         value="Code can only consist of alphabets and no spaces" />

                 </td>
                 </tr>
           
                </table>  
                </div>   
            </s:validateAll>
        </rich:panel>
    </h:form>

 

 

That's it. Now as the user types, onValid and onInValid handlers in setMask() are fired guiding him as he types. If he plays dumb and tabs out, the Hibernate validators on the model will still stop him.

 

Please read my original post in the forum in http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4209272 as a reference. Thanks to Sergey for helping me remember that my mask and JS events were attached to the DOM and I needed to reattach my setMask call after the a4j:support event.

 

Now if you are thinking if this is a crummy example - why do I need it at all ? you have a good point. A regex pattern on the model should be good enough. But you can apply this example here to implement a password policy where you have a password and a retype password field that can be validated on the client side.

 

If you do not need the event handlers and just need the masks, you can do that. Here is another example where I set up masks for some numeric fields - you can put this in a setMask function.

 

           //use meiomask to set input masks
           jQuery.mask.masks = jQuery.extend(jQuery.mask.masks,{
                msrpmask:{ mask: '99.999999', type : 'reverse'},
                   lsppgmask:{ mask: '99.999999', type : 'reverse'},
                   inventorymask:{ mask: '999999', type : 'reverse'}
            });

 

            //then call this to activate masks lib        
            jQuery('input:text').setMask();

 

 

 

Good luck

Franco