Update on 09-09-2013: shortly after I wrote this article, I created the APEX Live Validation plugin.
Something that I really miss in APEX development is out-of-the-box support for client-side form validation. Most web applications these days make use of live validations written in JavaScript to instantly inform the end user on incorrect input. This greatly improves the usability and performance of your system since you avoid the user from submitting obvious erroneous data to the server. Don’t get me wrong; client-side validation is not a substitute for server-side validation. It’s simply too easy for an end user to bypass the JavaScript-driven validations.
Creating server-side validations in Oracle APEX is simple and fast. Common validations (e.g. not null, is numeric, is a valid date, etc.) are implemented in a declarative way, while other more complex and custom validation logic can be written in SQL or PL/SQL code. Declarative support for client-side validation in APEX is nonexistent. So we’ll have to write all logic in JavaScript/jQuery code ourselves. Sounds like a lot of work, right? Well, not really. Read on and allow me to explain you how to build a structured and reusable client-side validation component.
Here’s how my end result looks like: demo.
1. Create a form on a table (or view)
In my example, I created a form based on the EMP table. Make sure to assign a static ID to the region that contains the page items and the region buttons that submit the page:
- I gave the region an ID of empForm.
- The button that updates an employee record has an ID of saveEmpBtn.
2. Determine what page items need validation
Go through every page item and think of what validation(s) should be performed. Meanwhile, properly specify all attributes per page item. For example, set Value Required to Yes for items that are required to fill in, or set the Display As attribute for numeric fields to Number Field. It’s important to do this because we’ll rely on these settings later on.
I decided to perform the following validations:
- Name: text field – required
- Department: select list – required
- Hiredate: date picker – required and valid date
- Salary: number field – required and positive non-decimal number
- Commission: number field – valid number
3. Write your validation logic
Create a reusable routine for each type of validation that you have to perform. Such a routine typically accepts a single parameter and returns a boolean. We’ll use these functions to check whether or not an input value is valid.
function isEmpty(pValue) { var isEmpty = false; if ($.trim(pValue) === "") { isEmpty = true; } return isEmpty; } function isPositiveInteger(pValue) { // an integer is a number that can be written without a fractional or decimal component var isPositiveInteger = false; var positiveIntegerRegex = /^\d+$/; if (pValue.match(positiveIntegerRegex)) { isPositiveInteger = true; } return isPositiveInteger; } function isValidDate(pValue) { var isValidDate = false; // date format is DD/MM/YYYY var dateFormatRegex = new RegExp("^(3[01]|[12][0-9]|0?[1-9])/(1[0-2]|0?[1-9])/(?:[0-9]{2})?[0-9]{2}$"); if (pValue.match(dateFormatRegex)) { // seems that the date format is correct, but can we parse the date to a date object? var dateArray = pValue.split("/"); var year = parseInt(dateArray[2]); var month = parseInt(dateArray[1], 10); var day = parseInt(dateArray[0], 10); var date = new Date(year, month - 1, day); if (((date.getMonth() + 1) === month) && (date.getDate() === day) && (date.getFullYear() === year)) { isValidDate = true; } } return isValidDate; }
Tip: There is plenty of code available online when it comes to validating forms with JavaScript. So take a peek at Google when you find it difficult to create such functions.
4. Bind validations on page load
We’ll use the onblur event to immediately perform one or more validations from the moment a user leaves an input field. The binding takes place after page load. A jQuery selector is used to accurately target the page items that need some sort of validation. The easiest way to come up with these jQuery selectors is by studying the generated HTML. Let me explain the selectors that I have used:
- $(‘[required]’) : Retrieves all page items that are required to fill in. This jQuery selector fetches all elements that have the required attribute. The required attribute is added to all elements for which the Value Required setting is set to Yes. This feature was introduced in APEX 4.2, so older versions need a different jQuery selector based on a custom CSS class. I’ll explain the concept of custom CSS classes straight away.
- $(‘input.number_field’) : Fetches all input fields with a CSS class of number_field. APEX automatically assigns this class to page items that are number fields.
- $(‘input.valPositiveInteger’) : This selector relies on a custom CSS class, valPositiveInteger. The difference between the previous CSS class is that the number_field class is added automatically by APEX for all number fields. The valPositiveInteger class however must be assigned manually in the HTML Form Element CSS Classes page item setting.
- $(‘input.datepicker’) : Selects all items of type Date Picker. The datepicker class is added automatically by APEX, so there is no custom CSS class required here.
// global variables var errorClass = "valError"; // bind validations on page load $(function() { $('[required]').blur(function(event) { if (isEmpty(this.value)) { showErrorField(this, "required field"); event.stopImmediatePropagation(); } else { hideErrorField(this); } }); $('input.number_field').blur(function(event) { if (!isEmpty(this.value) && isNaN(this.value)) { showErrorField(this, "not a numeric value"); event.stopImmediatePropagation(); } else { hideErrorField(this); } }); $('input.valPositiveInteger').blur(function(event) { if (!isEmpty(this.value) && !isPositiveInteger(this.value)) { showErrorField(this, "not a positive integer value"); event.stopImmediatePropagation(); } else { hideErrorField(this); } }); $('input.datepicker').blur(function(event) { if (!isEmpty(this.value) && !isValidDate(this.value)) { showErrorField(this, "not a valid date (DD/MM/YYYY)"); event.stopImmediatePropagation(); } else { hideErrorField(this); } }); });
5. Error message manipulation
You probably noticed the showErrorField and hideErrorField functions in the previous code snippet. The logic is pretty simple:
- showErrorField inserts a span element accompanied by an error message behind a given input field. I also add an error class to the input field which makes it easy to apply certain CSS styles to it.
- hideErrorField removes the span element and error class, if present.
function showErrorField(pInputElement, pMessage) { var inputElement = $(pInputElement); if (!inputElement.hasClass(errorClass)) { inputElement.addClass(errorClass); inputElement.after("<span class=\"" + errorClass + "\">" + pMessage + "</span>"); } else { inputElement.next().text(pMessage); } } function hideErrorField(pInputElement) { var inputElement = $(pInputElement); if (inputElement.hasClass(errorClass)) { inputElement.removeClass(errorClass); inputElement.next().remove(); } }
6. CSS
Some CSS code to visually mark an input field as erroneous.
input.valError, textarea.valError { background-color: #FAE7E7; } span.valError { margin-left: 5px; color: #c60f13; }
7. Before page submit
The live validations on our form are now operational. Filling out an input field with an invalid value results in signaling the end user by displaying an appropriate error message. This certainly is an improvement in terms of user-friendliness. It is, however, still possible for the user to submit the form to the server while it contains obvious errors. We’re going to avoid this behaviour by (re-)executing all form validations on the moment our user hits the submit button. The form won’t get submitted if one or more errors exist. The formHasErrors function checks if a form contains errors.
function formHasErrors(pForm) { var errorsExist = false; var formElement = $(pForm); formElement.find('input, textarea, select').trigger('blur'); if (formElement.find('.' + errorClass).length > 0) { errorsExist = true; } return errorsExist; }
Next, we have to intercept the onclick event on the button that submits the form. To do so, we first save the original onclick event of the button (by using jQuery.data) and we then replace the onclick event with a function that evaluates the formHasErrors function:
- if TRUE; alert the user that the form contains errors and certainly do not submit the page
- if FALSE; execute the original onclick event
function validateFormBeforeSubmit(pForm, pFiringElement) { var firingElement = $(pFiringElement); var originalOnclickEvent = firingElement.attr('onclick'); firingElement.data('origOnclickEvent', originalOnclickEvent); firingElement.removeAttr('onclick'); firingElement.on('click', function() { if (!formHasErrors(pForm)) { eval(firingElement.data('origOnclickEvent')); } else { alert("Please fix all errors before continuing"); } }); }
The validateFormBeforeSubmit function accepts two parameters with the purpose to identify the button(s) that are responsible for form submission. Creating this connection allows us to revalidate the coupled form before page submit. Both parameters represent a jQuery selector (remember the static ID’s in step 1). Place the code below in the Execute when Page Loads section on page settings.
validateFormBeforeSubmit('#empForm', '#saveEmpBtn');
8. Wrap it up
Put all JavaScript code, except the last snippet, in one file and include it on all pages throughout your application. The best way to do this is by referencing the JavaScript file in your page templates. You now have a highly reusable client-side validation library at your disposal which can be easily extended. Check out the end result here.
Can u please explain how can i validate email in oracle apex 4.2 ? please explain with code……..
LikeLike
Hey Ranait,
Well, I’d use the ALV APEX plugin since it includes e-mail validation out of the box.
Anyway, here’s a JavaScript function that validates an e-mail address:
LikeLike
Hi Nick I’m Jeffy
I want to ask about validation date in your function
function isValidDate(pValue) {
var isValidDate = false;
// date format is DD/MM/YYYY
var dateFormatRegex = new RegExp(“^(3[01]|[12][0-9]|0?[1-9])/(1[0-2]|0?[1-9])/(?:[0-9]{2})?[0-9]{2}$”);
if (pValue.match(dateFormatRegex)) {
// seems that the date format is correct, but can we parse the date to a date object?
var dateArray = pValue.split(“/”);
var year = parseInt(dateArray[2]);
var month = parseInt(dateArray[1], 10);
var day = parseInt(dateArray[0], 10);
var date = new Date(year, month – 1, day);
if (((date.getMonth() + 1) === month) && (date.getDate() === day) && (date.getFullYear() === year)) {
isValidDate = true;
}
}
return isValidDate;
}
what if I change date format from DD/MM/YYYY to DD-Mon-YYYY
can you tell me How to change it ??
please answer my question as soon as possible
thanks
LikeLike
Hi Jeffy,
The MON part in your date format is kind of tricky. My date validation function is too limited to handle that specific date format. As an alternative solution, take a look at the following JSFiddle: http://jsfiddle.net/YuDE8/4/
It includes a JavaScript function to validate a DD-MON-YYYY date format.
Source: http://stackoverflow.com/questions/18659614/using-regexp-to-validate-a-date-using-dd-mon-yyyy-format
Hope that helps,
Nick
LikeLike
So I just change your date validation function to like this :
function isValidDate(pValue) {
if (pValue== ”) return false;
//Declare Regex
var rxDatePattern = /^(\d{1,2})(\/|-)(?:(\d{1,2})|(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec))(\/|-)(\d{4})$/i;
var dtArray = pValue.match(rxDatePattern);
if (dtArray == null) return false;
var dtDay = parseInt(dtArray[1]);
var dtMonth = parseInt(dtArray[3]);
var dtYear = parseInt(dtArray[17]);
if (isNaN(dtMonth)) {
for (var i = 4; i <= 15; i++) {
if ((dtArray[i])) {
dtMonth = i – 3;
break;
}
}
}
if (dtMonth 12) return false;
else if (dtDay 31) return false;
else if ((dtMonth == 4 || dtMonth == 6 || dtMonth == 9 || dtMonth == 11) && dtDay == 31) return false;
else if (dtMonth == 2) {
var isleap = (dtYear % 4 == 0 && (dtYear % 100 != 0 || dtYear % 400 == 0));
if (dtDay > 29 || (dtDay == 29 && !isleap)) return false;
}
return true;
}
LikeLike
Yeah, looks good.
LikeLike
I just change your function to do like that,
but when I run it, it doesn’t nothing ??
LikeLike
Difficult to say what’s going wrong. Can you put some console.log() statements in your code? That way, you’ll be able to trace down the actual problem.
LikeLike
ah forget I just change your function to like this :
function isValidDate(pValue) {
var isValidDate = false;
// date format is DD/MM/YYYY
var dateFormatRegex = new RegExp(“^(1[0-2]|0?[1-9])/(3[01]|[12][0-9]|0?[1-9])/(?:[0-9]{2})?[0-9]{2}$”);
if (pValue.match(dateFormatRegex)) {
// seems that the date format is correct, but can we parse the date to a date object?
var dateArray = pValue.split(“/”);
var year = parseInt(dateArray[2]);
var month = parseInt(dateArray[0], 10);
var day = parseInt(dateArray[1], 10);
var date = new Date(year, month – 1, day);
if (((date.getMonth() + 1) === month) && (date.getDate() === day) && (date.getFullYear() === year)) {
isValidDate = true;
}
}
return isValidDate;
}
I change date format to be MM/DD/YYYY
and it’s work !
Thanks for your advice and your client side form nick
LikeLiked by 1 person
ah I forgot something to ask, what about when I put it in tabular form ?
is it posible to try your date validation function nick ?
LikeLike
It is possible to apply client-side validations to tabular forms. You can add CSS classes and custom attributes to your tabular form columns. For example, add the class “number_field” to a column’s “CSS Classes” attribute when you want to check for a valid number. It’s just a matter of linking a validation function to a tabular form column.
LikeLike
How I add CSS classes and custom attributes to my tabular form ?
Can you explain me for detail ?
LikeLike
Simply open the details of a tabular form column. Then, under “Advanced”, you’ll see the “CSS Classes” and “Custom Attributes” fields. Enter “number_field” in the “CSS Classes” field. The tabular form column input items will then have the “number_field” CSS class assigned. That’s how you couple a JavaScript validation function to a tabular form column.
LikeLike
so I just put like this ?
http://tinypic.com/r/mb36tu/9
I just put “datepicker” in the “CSS Classes” from date field in my tabular form. is that right ??
LikeLike
The column definition page from your screenshot is not the column definition page of a standard tabular form. Are you using a manual tabular form? Meaning that you created a classic report component, combined with APEX_ITEM package calls in your report query?
In that case, use the “p_attributes” parameter in your APEX_ITEM calls to add the “datepicker” class to your input items. Something in the form of: p_attributes => ‘class=”datepicker”‘
LikeLike
Your blog was basically useless to me, a relative novice to APEX; because you failed to where to place all of the code?
LikeLike
– Put all JavaScript code in one file
– Upload that file in Shared Components > Static Application Files
– Include the JavaScript file on the pages you want client-side validations for (page settings > JavaScript > File URLs)
Do the same for the CSS code, but include the CSS file under page settings > CSS > File URLs.
LikeLiked by 1 person
Form was being submitted twice until I commented out //eval(firingElement.data(‘originalOnclickEvent’)); Still have a problem. When trying to submit a blank form, all errors are displayed, warning to “Please fix all errors before continuing” is shown, form is submitted anyway. I have two optional fields on my form, if that matters.
LikeLike