Agile Tortoise
Greg Pierce’s blog
« Magnetic ribbons Happy Birthday, Sweetie! »
Servoy: turning global form events into callbacks
Using global methods for form events provides a simple way to build consistent interfaces across your solution while maintaining DRY principals. Servoy's latest 3.5 release includes form event templates, which makes it even easier to apply a set of global events to new forms. There's always cases, however, where you have behaviors that are specific to particular forms and can't be abstracted to globals. This is a perfect opportunity to use callbacks.
So my solution to making a maintainable set of generic global form events is based on turning the events into a set of callbacks on forms that follow a basic naming convention, and if they callbacks are defined, they are called -- if not, the default event behavior is used. For those who just want to cut to the chase, I've included a demo solution for download -- just import into Servoy 3.5:
First, you'll need methods to determine if a form exists, and if a method by a particular name is defined on that form. Here are mine:
-
// form_exists - returns boolean
-
eval('forms.'+arguments[0]);
-
return forms[arguments[0]] ? true : false;
-
// form_has_method - returns boolean base on form/method name passed
-
var frmName = arguments[0];
-
var methodName = arguments[1];
-
-
if( !globals.form_exists(frmName) )
-
return false;
-
return utils.stringLeft( typeof(forms[frmName][methodName]), 7 ) == 'functio' ? true : false;
Now you can utilize those methods to check if the callbacks you want to use are defined on a form, and call them in your global form events. Here's an example global form event method for the "onNewRecord" event:
-
// form_event_newRecord
-
// get calling form name...
-
var frm_name = application.getMethodTriggerFormName();
-
-
// use new security methods to check if the user can create a record
-
if( !security.canInsert(currentcontroller.getServerName(), currentcontroller.getTableName() ) )
-
{
-
plugins.dialogs.showErrorDialog( "Error", "Permission error", "OK" );
-
return;
-
}
-
// if a 'canInsert' method is defined, call it -- it should return a boolean
-
if( globals.form_has_method( frm_name, 'canInsert' ) )
-
{
-
if( !forms[frm_name].canInsert() )
-
return;
-
}
-
// this is optional, depending on your requirements
-
databaseManager.saveData();
-
-
// if 'form_event_newRecord' is defined on the form, use it to create the record
-
// otherwise, use the controller.newRecord default
-
if( globals.form_has_method( frm_name, 'form_event_newRecord' ) )
-
forms[frm_name].form_event_newRecord();
-
else
-
forms[frm_name].controller.newRecord(false,true);
-
// if 'form_event_initRecord' is defined, call it. use this callback to set values on the record
-
if( globals.form_has_method( frm_name, 'form_event_initRecord' ) )
-
forms[frm_name].form_event_initRecord();
-
return;
The demo solution also has examples for 'onDeleteRecord' and 'onRecordSelection' -- the later I use to implement record-level security through callbacks. I have a full set of the methods for all standard events which I utilize in my solutions. Then, I just don't really think about events -- just that I have a callback chain. The callback chain in the above 'onNewRecord' example is: 'canInsert' (return false to prevent creation), 'form_event_newRecord' (override the default controller.newRecord behavior), 'form_event_initRecord' (set default values on the new record).
I'm interested to hear if people are doing similar things, or think this is a valueable technique.
November 10th, 2007 at 12:08 pm
This is cool. I hope you participate in the Servoy Best Practices wiki begun by Robert Ivens of ROCLASI … to which I have contributed a little bit of writing thus far in a weak attempt to help, but I have little technical expertise to contribute, sadly. See wiki.servoyforge.net — I would be very interested in reading discussion there between the “do not use method-naming conventions to ‘objectivize’ methods” camp, and those who happily go ahead and do just that … and to watch what collaboratively defined best practices result.