Oct 22

We’re all eagerly awaiting APEX 4.0 and the new functionality, i.e. including tabular form validations. However some of us just can’t wait to see what we are going to get, so we end up doing/writing our own version first, which will probably be superseded and a total waste of time but that’s what we as developers do!

In our integration framework we found it very easy to enable the functionality in the tabular form since we’d already worked out the column mapping of DOM id’s/names for the tabular form input elements to their corresponding column (see our previous tabular form post), all we needed to do was put some additional information in our JSON meta data object in the page header to reference in our javascript transform routine which converts the normal input items e.g. select lists, date pickers etc into our ext equivalent ones.

To recap from previous posts, we create a tabular form using the APEX IDE and simply change the region & report template to our Ext custom templates which we have created. The templates render the APEX tabular form in an Ext grid. Each time the grid (re)loads we fire off an onload event which takes the DIV container ID of our Ext grid and uses an Ext.select to grab all the input items within it to transform into Ext equivalents. This transform function uses metadata in the page header to work out what transform to perform, i.e. Date, Textfield, Select List, Popup LOV etc. it also uses this meta information to set a number of Ext config parameters for the widget. This means we can easily set a vtype config parameter and enable a dynamic validation.

So our JSON meta data object in the page header contains the following fragment, which pulls the required vtype from the comments section of our tabular form column looking for the following syntax: $vtype:[validation] e.g. $vtype:email$

"vtypes" :
{ "f03" : "email" }

And our transform function just does the following (this is an example for a textfield):

try {
   var lvType = eval("pMetaObj.vtypes." + el.dom.name);
} catch(e) {
   var lvType = null;
}
var tf = new Ext.form.TextField({
   "id": el.dom.id,
   "vtype": lvType,
   "allowBlank": lAllowBlank,
   "applyTo": el.dom.id
});
tf.render();

The end result then looks like this:

APEX Tabular Form - Dynamic Validatons using vtypes

In summary we think we’re on the right track with our framework design approach, simply because it doesn’t take us very long to implement new functionality, and its easy to maintain and update since it uses a single source and write once approach. We’d recommend a similar design if you’re looking to replicate the functionality or develop improved solutions. In essence its really just replicating the design of APEX client side, store everything in metadata and build everything on the fly through reusable api’s. i.e. store your meta data in JSON and reference it in your javascript when you build or transform page components… simple and a recipe for success because that’s what APEX is!

Jun 22

I’m a fan of Apexlib, and it’s geen a great utility for providing some of the missing functionality APEX was lacking. One of those features was dynamic validations for “not null” and “date format” form fields. With the integration kit we are building we are looking to offer an Ext equivalent of everything Apexlib provides “and more” so this is one of the tasks we needed to deliver. The effort required to achieve this? Not much at all… since we transform our (tabular) form elements (one of our earlier posts) into Ext equivalent fields we get the benefit of using config settings such as “allowBlank” and “format” which do the validations for us. All thats required is that we set these config values accordingly.

When a validation failure occurs we simply disable the grid top toolbar so the page can’t be submitted and thus resulting in a reduction of required server side validations (but of course it doesn’t hurt to have them in case of an unexpected page submission, especially when not null ones are auto generated by the APEX engine for you). It’s just a nicer experience for the end user when they don’t have to submit pages all the time, not to mention less server side processing.

Here’s our function to transform our form date fields into an Ext equivalent

// convert inputs with class "ext-form-date-picker" to date fields
function extGridDateFields(pID, pRptMetaObj, pGridValidate, pGridValCollection) {
   var els = Ext.get(pID).select("[class=ext-form-date-picker]");
   els.each(function(el) {
      if (el.dom.className.indexOf("aext-form-date") == -1) {
         try {
            var lFormat = eval("pRptMetaObj." + el.dom.name + ".dateFormat");
            var lAllowBlank = eval("pRptMetaObj." + el.dom.name + ".nullable");
         } catch(e) {
            var lFormat = 'd-M-Y';
            var lAllowBlank = true;
         }
         el.dom.className += " " + "aext-form-date";
         var df = new Ext.form.DateField({
            "allowBlank": lAllowBlank,
            "applyTo": el.dom.id,
            "format": lFormat,
            "altFormats": 'j|j/n|j/n/y|j/n/Y|j-M|j-M-y|j-M-Y'
         });
         df.render();
         if (pGridValidate) {
            df.on({
               "invalid": function(field, msg) {
                  gridFieldInvalid(pID, pGridValCollection, this, msg);
               },
               "valid": function(field, msg) {
                  gridFieldValid(pID, pGridValCollection, this, msg);
               }
            });
         }
      }
   })
}

And here’s the supporting validation code (we use an Ext Mixed collection to keep track of the validation error, when none exist the top toolbar is enabled, when one or more exist the top toolbar is disabled).

function gridFieldInvalid(pGridID, pCollection, pField, pMsg) {
   if (!pCollection.key(pField.id)) {
      pCollection.add(pField.id, pField);
   }
   Ext.getCmp(pGridID).getTopToolbar().disable();
}
function gridFieldValid(pGridID, pCollection, pField, pMsg) {
   if (pCollection.key(pField.id)) {
      pCollection.removeKey(pField.id);
   }
   var isEmpty = true;
   pCollection.each(function() {
      isEmpty = false;
   });
   isEmpty ? Ext.getCmp(pGridID).getTopToolbar().enable() : Ext.getCmp(pGridID).getTopToolbar().disable();
}

How do we know what is nullable and what requires date formats? We query the database data dictionary using the defined values under the column attributes for each column in the report. We then add the details for any columns which require validations to our existing JSON report meta data object which we print out in our page header. We get the benefit of two metadata dictionaries with APEX, the application and the database. I think the emerging trend of “thick databases” will start to take hold when more people realize the main benefits are reduced development time and costs…. two of the most important things in today’s climate!

APEX ExtJS - Tabular Form Dynamic Validation

preload preload preload