In this article I will demonstrate how to easily improve the server side form validation process from a user’s perspective.
Introduction
I have to admit that I am not a fan of server side validation. While it suits the developer, it is often not a good user experience. If you complete a large form, hit submit and you have errors returned, it is had to ascertain where the error has occurred. This causes the user to have to scroll up and down the page looking for the error. In an ideal world the form needs to be validated fornt end and back end to provide the optimal experience, while ensure data integrity within the application.
When building the PSC Contest site http://contest.psclistens.com I wanted to make the server side validation as painless as possible for users.
Basic Server side XPages validation
To validate a field on an XPage we use validators and a custom message. In the following example, when the user submits a blank field, an error message will be returned and the JSF validation will prevent the form from saving.
<xp:inputText styleClass="form-control" disableTheme="true" value="#{competition.First}" id="first1"> <xp:this.attrs> <xp:attr name="placeholder" value="Contact First Name"> </xp:attr> </xp:this.attrs> <xp:this.validators> <xp:validateRequired loaded="true" message="This value is required"> </xp:validateRequired> </xp:this.validators> </xp:inputText> <xp:message id="message6" for="first1" styleClass="error"> </xp:message>
Here is an example of the failing field. I have assigned a class = “error” to the message and that styles it red and bold.
Scrolling to the error message
Within the onComplete event of the form’s submit button we can add some code to determine if there are any errors. If there are errors we can use some jQuery to “scrollTo()” the message on the screen and it is revealed to the user.
- The code var temp = $(‘.error:visible’) selects all the error message which are visible to the user.
- If the length of the selector is greater than 0 there must be an error on the page
- So determine where it is on the page temp.eq(0).offset().top-250 and then
- Animate a scroll to the element.
- http://api.jquery.com/scrolltop/ tells us that we are able to ascertain the scroll bar height of the element and “Setting the scrollTop positions the vertical scroll of each matched element.”
<xp:button value="Submit" styleClass="btn btn-primary theSubmit" id="button1"> <xp:eventHandler event="onclick" submit="true" refreshMode="partial" immediate="false" save="true" refreshId="container"> <xp:this.onComplete> <![CDATA[ //Check to see if there are any errors var temp = $('.error:visible') if (temp.length >0){ $('html, body').animate({scrollTop: temp.eq(0).offset().top-250}, 1000, function(){ }); } else { alert('Thank you for your submission. PSC will be in touch.') location.href="http://www.psclistens.com" } ]]> </xp:this.onComplete> <xp:this.script><![CDATA[ //check to see if project sponsor is checked if ($('.projectSponsor').is(':checked')){ console.log('sponsor check') app.checkSponsor() } ]]></xp:this.script> </xp:eventHandler> </xp:button>
If there are no errors the user is thanked and redirected to the PSC homepage.
Don’t do a complete submit….
The only way we are able to run an “onComplete” on the button event handler is if we do not submit the entire form. If we do this then all the code will be lost and the page will revert to the top of the page.
Wrap the body of the form in a panel or div which can be refreshed. Set the button click to partial refresh that section. This way the scroll position on the page will not be lost when the button is clicked.
The contest site
Check out the contest site http://contest.psclistens.com before 13 Feb 2015 when PSC will announce the winner
May I suggest also focussing the cursor IN the first field that needs the users attention?
OH DUH
makes perfect sense – thank you Bruce
Done and implemented
Which btw was one line of code – due to the consistent way the form is structured it is easy to find the field related to the error.
From the error message – go up to the container DIV and then find the for form-control within.
Love me some jQuery 🙂
temp.eq(0).closest(‘div’).find(‘.form-control’).focus()
Very nice!
Nice post Mark, thank you for sharing.
Gotta love JQuery. With it, you can make your application look professional and pleasing.