APEX Client-Side Validation

There is a new little known sorta feature in APEX 5.1 called client-side validation. You may have missed it because it is not listed in the release notes under new features and only mentioned cryptically, almost tangentially, in the release notes section “Compatibility Mode Changes in Mode 5.1”. It says

“… buttons where the Execute Validations attribute is set to Yes also perform some client-side validations (such as item required checks) and will not submit the page until all issues are fixed”

Other hints and evidence for this feature are the new apex.page.validate function, the validate option to apex.page namespace submit and confirm functions, and the new apex.item getValidity and getValidationMessage functions.

I mentioned client-side validation and how Interactive Grid was the motivation for it in Interactive Grid Under the Hood. However it is likely you fell asleep before getting to the end where I briefly mention it. There is little documentation explaining the feature. To be fair it has been mentioned in many APEX conference presentations, mostly of the what’s new variety, and a few other blogs as well. There are also a few examples in the Sample Interactive Grids app that I highly recommend you check out.

It is also possible that you just stumbled upon the feature when you created a new app (so compatibility mode is 5.1) with a page with a required page item and a submit button with execute validations = yes. Then ran the page, forgot to enter a value, pressed the submit button and were surprised, perhaps pleasantly so, to see this dialog

Validation Dialog

The reason I called it a sorta feature is because it is really half-baked or more kindly a work in progress. It only validates required fields and even then it is broken in some item types such as checkbox. It has some limitations around translations that Marko explains how to work around. It is also not easy to opt out of. My hope is that this feature will improve over time.

The rest of this article is about how it works and examples of what you can do with it. I also provide my own personal thoughts on what would make the feature better. I need to stress that even though I work on the APEX development team these are my opinions and should not be considered part of the product road map.

Before getting into client-side validation lets review server-side validation. APEX lets you create validations for any of the data a user can enter. Some validation types are fully declarative such as “Item is numeric” others let you write SQL expressions or PL/SQL code. All the APEX App Builder UI where you declare validations makes no mention of it being server-side. From a historical perspective there is no confusion because that is all there was. If there is any doubt, the validation types of SQL Expression and PL/SQL Function should remove it, as they can only run on the server. It is crucial that validation be done on the server to protect the integrity of application data. This is because of the inescapable fact that web clients can’t be trusted.

Given that validation MUST be done on the server why bother also doing it on the client? There are 2 reasons.

  • The first is faster response time for the user. Checking inputs on the client avoids the time delay for the round trip request to the server in the case there is an error. It is also possible to let the user know about mistakes as soon as they leave a field or cell rather than having to wait until they submit the page. This also reduces network traffic and load on the server.
  • The second has to do with preservation of client state. Once the page is submitted (the form is sent to the server as a normal POST request) the client page context is gone and will be replaced with a new page. If there are errors the same page is regenerated and returned with error messages included but there is plenty of client side state that the server has no way of knowing about and therefore can’t recreate. This includes focus, last focus for focus managed widgets, scroll offsets, selection state for form elements or widgets that support selection, and some form field values such as password and file. A related issue is that the usual redirect after post cannot be done so the current URL is the post request and it is included in the browser history. The redirect after post pattern, also known as post-redirect-get, alleviates problems of bookmarking, duplicate form submission, and browser back button navigation. When there is a validation error all benefits of redirect after post are lost. For successful requests only the optional success message need be communicated between the current and next page. (Notice how this is handled with the success_msg parameter in the URL.) With validation errors there is far too much information to pass on to the next GET request.

This second issue is a big problem for the new Interactive Grid feature because it has a large amount of client side state that the server could not reasonably reproduce when regenerating the page with error information. Think about a page with master and detail Interactive Grids where several detail rows corresponding to several different master rows possibly spread across different grid pages in either of the grids are edited. The state that would be lost includes last focused cell, selection, and scroll offsets in two Interactive Grid regions as well as all the underlying data models. Although client-side validation removes the problem, as will be clear in a moment we cannot rely on it completely. The primary solution that APEX uses to avoid this problem is to use ajax to “submit” the page. This new 5.1 change in behavior is explained very nicely in this video by Martin.

Even with the ajax page submission it is still worth while to do client-side validation for the first reason – more timely validation messaging for the user. But not all validation can be done on the client. This includes validations that are complex or rely on data that must not leave the server for performance, security, or privacy reasons.

With a mix of client-side and server-side validation it is important that the validation messaging be consistent. This along with the new ajax page submission meant that we needed a new client-side messaging facility; a way to add page level and inline validation messages to a page after it has left the server. See the apex.message API. Anthony gives a very good tour of this facility by showing how to add support for client-side messaging to your own custom theme.

APEX client-side validation uses the HTML5 constraint validation attributes and API. You can learn about this native form validation many places including MDN. PPK has done extensive research into cross browser support for native form validation and has written a three part series (2 of 3 complete as of the time of this article) that provides an excellent tour and critique of the feature. Native form validation has a number of issues most notably around messaging but the core is well supported by all modern browsers. The messages and how they are displayed are browser specific. They are in the browser’s locale rather than the APEX application’s locale. APEX leverages the useful parts of native form validation and overrides the rest. Specifically it lets the browser do its native validation based on validation attributes such as required and pattern and lets the browser be the keeper of an item’s validity. It uses the element validity and validationMessage properties via the apex.item API getValidity and getValidationMessage functions. It provides a way to override the validation message using the data-valid-message attribute but this is not yet well integrated with APEX translations or consistent with server defined validation messages. APEX uses its new client messaging facility to display validation error messages rather than the native browser specific functionality. This makes the message display placement consistent between client and server validation and across browsers. It does this by setting attribute novalidate on the form element.

Finally here are some examples of how to implement client-side validation in your APEX apps. To start with application compatibility mode must be 5.1 or greater and the button Behavior: Execute Validations attribute must be Yes. Execute Validations also applies to server-side validations as it always has. This results in option validate: true being passed into the apex.submit function in the button’s click handler, which internally calls apex.page.validate. It is also possible to call apex.submit from JavaScript with the validate option being true or false depending on if you want to run client-side validations on the page before it is submitted. Oddly the Dynamic Action (DA) action Submit Page does not give you the option of validating. If you need to validate from a DA use a JavaScript action and call apex.submit. When you call apex.submit directly the compatibility mode has no effect; it only affects the interpretation of the Execute Validations attribute.

Because Execute Validations attribute applies to both client and sever validation it is not easy to opt out of client-side validation. Assuming you want compatibility mode to be >= 5.1 one way to do this is change the button from a Submit Page action to a Dynamic Action that does Submit Page.

The simplest thing to do is validate required fields. Simply set the page item’s Validation Value Required attribute to Yes. This works because it adds the HTML required attribute which is part of native form validation. As mentioned above there are some bugs in how some item types handle client side validation so for Popup LOV, Radio Group, Checkbox, or Shuttle you may need to set Required to No and rely on an “Item is NOT NULL” validation.

For text fields you can choose E-Mail or URL for attribute Settings: Subtype. This will validate that the input is a valid email address or URL respectively. This automatic validation is due to the built in semantic validation based on the input type.

You can optionally add data-valid-message=”Employee Name is required” (or whatever text makes sense) to attribute Advanced: Custom Attributes to override the message displayed when there is any client validation error. This is true for all the client validation cases. This is an area that I hope gets improved in the future. It should be more declarative rather than rely on the general purpose Custom Attributes setting. The biggest problems are translation and consistency with server-side validation messages. An item can have multiple validations but there is currently a single message attribute. This reflects the UX principal that it is better to state what is expected rather than what the user did wrong. For example consider a required field that must be an even number. The user leaves it blank and they are told it is required. So they enter “yes” and are told it must be an integer. So they enter 1 and are told it must be even. Finally they enter 2 and get it right. Wouldn’t it be better to say “An even integer is required” from the start. You could argue that this rarely happens because the user should know what to enter based on the label, placeholder, inline help text, or general context. I still believe it is a reasonable principal. It is not clear how to resolve this with the way server side validation messages currently work (each validation has its own message). In my experience this issue has a major influence over how validation systems are designed.

The next simplest kind of client validation is to use one of the other HTML5 validation attributes. The most useful one is pattern. (The min, max and step attributes only work with number or date inputs and we do not use these input types because the UI is inconsistent across browsers and/or undesirable.) For example, to validate that a text field does not allow spaces, set attribute Advanced: Custom Attributes to:
pattern="[^ ]*" data-valid-message="No space allowed"

Finally there is custom validation using JavaScript. The general idea is to use the HTML5 constraint API setCustomValidity function. Note that just like with the HTML5 declarative attributes above, when the field is validated is independent from when the validation error is reported (displayed). A good time to do the validation is when the page loads and when the field losses focus. The error is reported when apex.page.validate is called, for example when the page is submitted.

This example validates that a number field is even. Create a DA on the Loose Focus event of a number field. Add a JavaScript function like the following.

var item = apex.item("P1_NUMBER"),
    val = item.getValue(),
    n = parseInt(val, 10);
if ( val.length > 0 && !isNaN(n) && n % 2 === 0) {
    item.node.setCustomValidity(""); // valid
} else {
    item.node.setCustomValidity("Invalid"); // rely on data-valid-message attribute to give nice message
}

Set the action Fire on Initialization attribute to Yes. Set the number field Advanced: Custom Attributes to: data-valid-message=”An even integer is required”.

That’s all there is to basic client-side validation of page items. Validating Interactive Grid column items is similar and you should explore the Sample Interactive Grids app Advanced: Client Validation page.

What has been shown so far only reports (displays) errors when the page submit button is pressed. This happens because the validate option of apex.page.submit calls apex.page.validate. The apex.page.validate function has a misleading name. It doesn’t do the actual validation. Meaning it is not evaluating any value constraints. Remember that in most cases, it is the browser that is doing the validation and it keeps the validity object up to date at all times. Recall that even the custom JavaScript validation was run when the field lost focus. The job of the apex.page.validate function is to report on all item validation errors on the page and return false if there are any errors so that the caller can for example not submit the page. It also checks if any apex.models (used by Interactive Grids) have any errors. It doesn’t report these errors because Interactive Grids report errors as cells loose focus. You can call apex.page.validate at other times if you just want to report on the validations.

Some people prefer that validation errors are reported as soon as the user leaves the field. I prefer this as well in most cases. However, this is not currently supported for page items. I started to work on this but it is not complete. You can see the work in progress in page.js function validatePageItemsOnBlur. This function has received very little testing and should not be used at this time but you could borrow ideas from it if you really wanted to implement this feature yourself. The general idea is after a field looses focus the apex.item getValidity function is called and if the item is not valid getValidationMessage is used to get the message to display. The apex.message.showErrors API is used to show the error. I hope this is something that gets completed in the future.

Tip: For anyone creating an item plugin you should implement the apex.item getValidity and getValidationMessage functions if needed so that the plugin will work with the APEX client-side validation feature.

The focus of native form validation is on individual fields. It doesn’t handle constraints involving multiple fields such as one value must be greater than another value or exactly one of two fields must be non null. In some cases you can work this into a single field validation by associating the custom constraint with one field that uses the value of other fields. If that does not work then you need to execute your own constraint check before the page is submitted. You can do this by using a DA on the button rather than Submit Page behavior. The DA would call apex.page.validate and if no errors do the additional checking and if that fails call apex.message.showErrors otherwise it would call apex.page.submit. Another alternative is to use a normal Submit Page button but add a DA on the Before Page Submit event. This DA doesn’t need to call apex.page.validate because it will happen after. It just needs to do the extra constraint check and if it fails call apex.message.showErrors and set apex.event.gCancelFlag = true so that the page is not submitted.

Earlier it was pointed out that not all validation constraints could be evaluated on the client. What if you wanted to execute some PL/SQL to validate a field. In most cases it is best to just wait until the page is submitted. Or you could use ajax such as with a DA Execute PL/SQL code action but there are a number of issues with this.

It makes no sense to do this just before the page is submitted (meaning just before, during, or after the apex.page.validate call). You would be making a request to the server to validate and then making another request to the server to validate and persist the data. Why not just make the second request that does all the validations. From the users perspective it will only make the page submission appear much slower (roughly double the time). Also keep in mind that the validation done with the first ajax request cannot be trusted by the second request. The client could change the data between requests. Server validation must be directly coupled with persistence.

If you implement validation (and reporting the validation error) at the time the field looses focus then it may be reasonable to make an ajax request for validation that can only be done on the server. (Validation that can be done on the client should just be coded as a custom JavaScript validation as shown above.) This would be implemented similar to the above custom JavaScript validation except that the validation is asynchronous. There will be a delay between the time the field loses focus and the time the asynchronous ajax request completes and setCustomValidity is called.

If you end up doing validation in an ajax request such as a Execute PL/SQL DA action or an Ajax Callback process you will notice that you now have coded the validation twice and in different ways. The validation must be done in the ajax action or process and also as a normal server-side validation. In the case of the ajax action or process you have the added burden of returning the error information. With the Execute PL/SQL DA action returning it in a hidden page item is about the only option. For an Ajax Callback PL/SQL process you should return, as JSON, a structure that the apex.message.showErrors function expects. This is something that I hope is made simpler in the future. You should not have validation code in multiple places. Ideally declarative APEX (server-side) validations would automatically apply the equivalent JavaScript client-side validation so that in most cases you don’t need to write any custom JavaScript validations and even in cases where you do they wouldn’t involve creating a DA; just the constraint expression.

One last topic that is related to validation is constraining user input so they can’t make a mistake. From a UX perspective anything you can do to keep the user from entering bad data in the first place is a good thing. A common and obvious example is using a radio group, switch, or select list rather than a text input field. Another example is specifying a Maximum Length on a text field so the browser won’t let the user type more than the allowed number of characters. In some cases it is useful to add custom behaviors to a text field that restricts the characters that can be added. For example if a field only allows digits then you could create an event handler that doesn’t allow non digit characters to be added. Strictly speaking the server cannot trust these kinds of constraints either. For example a text field with a Maximum Length set can have a longer string explicitly set using JavaScript. Unlike the page item Validation: Value Required, which does an implicit NOT NULL validation on page submit, Maximum Length does not. You can add one if needed or rely on the underlying database length constraints to throw an exception.

Leave a Reply

Your email address will not be published. Required fields are marked *