Validating fields on the Connections profile

A customer of mine recently replaced their company directory by the profiles of Connections. They were using Connections for quite a while already, but to change details, like telephone numbers, office location etc, users had to make changes through the company directory system. This change posed a problem. Where the previous system had some input validation checks, Connections is all about full freedom for the users, so by default there’s no validation on any field. It turned out that this type of freedom was a bit too much for some users. A lot of users, for example, thought their office was based in a different city than it actually was. Also users were very creative in entering telephone numbers where they used all letters of the alphabet. I was therefore asked to change the profile form to add some validation checks, starting with telephone numbers and email addresses. I was given two limitations:

  • Connections Customizer was not installed
  • I was not allowed to make any changes to the profiles ear-file

This meant I had to limit my changes to the .ftl files, in particular profileEdit.ftl and commonUtils.ftl, and the custom.css (I cheated a bit and also added some custom images). I wouldn’t have been able to do this without the help from the community and in particular Martin Schmidt. If this article helps you solve your problem, please check out his Twitter account and thank him for it. Martin showed me how to change the commonUtils.ftl file to render some fields differently from other fields, use standard html 5 for validation and how to include a bit of JavaScript in a .ftl file. That left as largest remaining puzzle how to prevent users from saving the profile if a field didn’t pass validation. As I could use JavaScript, that puzzle was solvable.

The end result looks like this:
Any field that doesn’t validate will show a red exclamation mark at the end, to tell the user that they have to correct this before they can save the form. While typing, they will see the red exclamation mark, until a field does validate in which case the green check-mark appears. On leaving the field the green icon disappears as I didn’t want to make a distinction between fields that didn’t have validation and correctly validated fields. On hovering over a field with validation an example of the expected format appears. For telephone numbers I left some freedom where a format like +31 (0)6 12 34 56-99 would validate, yet a format like +31 6 —- 3343 or 0765332 (too short) would not pass. The Save and Save and Close buttons would be disabled until all exclamation marks are gone. Either by correcting the values or by emptying the fields as an empty value is also valid (user don’t *have* to disclose their phone numbers).

So here’s how I did it. The crux in the commonUtils.ftl file is this part in the #macro renderFormControl section where normal text fields are rendered:

<#else>
   <input value="${value}" type="text" class="lotusText<#if isBidiTextDir> bidiAware </#if>" id="${ref}" onchange="dataChange(this);" onkeypress="dataChange(this);" name="attribute(${ref})"/>
</#if>

I replaced that part with this:

<#else>
  <#if renderLabelAs== "phone">
      <div class="phoneNumber">
          <input value="${value}" type="tel" class="lotusText<#if isBidiTextDir> bidiAware </#if>" id="${ref}" onchange="dataChange(this);" onkeypress="dataChange(this);" oninput="validateFields();" name="attribute(${ref})" placeholder="+31 6 12345678" pattern="^(?:0|\(?\+[1-9][1-9]?[1-9]?\)?\s?|00[1-9][1-9]?[1-9]?\s?)[1-9](?:[\-\s]?\d\d){4}$" title="e.g. +31 6 12345678"/>
      </div>
  <#elseif renderLabelAs== "email">
      <div class="email">
          <input value="${value}" type="email" class="lotusText<#if isBidiTextDir> bidiAware </#if>" id="${ref}" onchange="dataChange(this);" onkeypress="dataChange(this);" oninput="validateFields();" name="attribute(${ref})" title="e.g. john.doe@gmail.com"/>
      </div>
  <#else>
      <input value="${value}" type="text" class="lotusText<#if isBidiTextDir> bidiAware </#if>" id="${ref}" onchange="dataChange(this); validateFields();" onkeypress="dataChange(this); validateFields();" name="attribute(${ref})"/>
  </#if>
</#if>

The renderLabelAs refers to information which I added to specific fields in the profileEdit.ftl file:

<@util.renderFormControl ref="mobileNumber" singleColumnLayout=false nlsKey="label.mobileNumber" renderLabelAs="phone"/>
<@util.renderFormControl ref="telephoneNumber" singleColumnLayout=false nlsKey="label.telephoneNumber" renderLabelAs="phone"/>

Also in the profileEdit.ftl file is my little piece of JavaScript to solve the save-button puzzle. This piece was added at the top of the file just under the first renderSection:

<@util.renderSection sectionLabel="contactInformation">
    <script type="text/javascript">
    function validateFields() {
        var validateElements = document.querySelectorAll("input[type=tel],input[type=email]");
        var disableSave = false;
        for (var i = 0, element; element = validateElements[i++];) {
                if (element.value != "") {
                        if (!element.checkValidity()) {
                                disableSave = true;
                                break;
                        }
                } // if
        } // for
        if(disableSave) {
                dojo.query("#editProfile input[ name = submitButton ]").forEach(function(el){
                        dojo.addClass(el, "lotusBtnDisabled");
                        dojo.setAttr(el, "disabled", "disabled");
                });
        } else {
                dojo.query("#editProfile input[ name = submitButton ]").forEach(function(el){
                        dojo.removeClass(el, "lotusBtnDisabled");
                        dojo.removeAttr(el, "disabled");
                });
        } // if
    } // function
    </script>
    <@util.renderFormControl ref="displayName" isDisabled=true singleColumnLayout=false nlsKey="label.displayName" isBidiTextDir=true/>

This leaves a bit of styling which I put in the custom.css:

/*profile*/
input[type="tel"]:required:invalid, input[type="tel"]:invalid, input[type="email"]:required:invalid, input[type="email"]:invalid { background-image: url("/com.ibm.lconn.core.styles.oneui3/hikariTheme/images/!.png"); background-position: 99% 50%; background-repeat: no-repeat; -moz-box-shadown: none; }
input[type="tel"]:focus:valid, input[type="email"]:focus:valid { background-image: url("/com.ibm.lconn.core.styles.oneui3/hikariTheme/images/Ok.png"); background-position: 99% 50%; background-repeat: no-repeat; -moz-box-shadown: none; }

The images I used are: and . You can grab them from here if you like them. If you use the css above, you have to put them in the images directory under the hikariTheme directory where your custom.css is located. Create the directory if it doesn’t exist yet.