O4W Form Commuter Module (Functions/Subroutines/Programs,Web)
Created at 11 SEP 2012 11:33AM
O4W Form Commuter Module
I. The O4W Form Commuter Module
In order to provide additional, and advanced, functionality to your O4W Form, you may choose to create and modify a "commuter module" that the form will invoke.
If you wish to use a commuter module, during the form definition process (on the "Behavior" tab) you _must_ check the "Call commuter module for events on this form?" radio button. You can then select which events you wish to be sent to the commuter module; choose which "form-level" events you would like to process from the "Events to call commuter module" section of the "Behavior" tab, and choose which "field-level" events you would like to process from the "Value Input/Display" popup of the "Edit/Display" tab. The form level events include "Pre-Read", "Post-Read", "Pre-Write", "Post-Write", "Pre-Delete", "Post-Delete", "Select", and "Tab". The field level events include "Entering field" and "Leaving field".
[Note that, while the temptation to add in EVERY event for EVERY control is great, this should be avoided if at all possible. While the underlying web technology behind O4W allows for much greater interactivity than the "web 1.0" straight-html forms of a few years ago, the web browser is NOT yet a replacement for the desktop, and attempting to have an O4W Form behave exactly the same as an OpenInsight (desktop-based) form - in terms of handling every event - will probably leave developers and end users alike frustrated. If for no other reason than Internet delays and slowdowns, interacting with the commuter module (which requires a "round trip" from the web browser to the web server, and additional processing time inside of OpenInsight, O4W, and the commuter module itself) can take a noticable time. For more performant forms (and therefore happier users), it is important to only 'capture' those events that need to be handled.]
At the end of the form definition process, you will be prompted to name the commuter module; you will also be prompted to have O4W automatically create and compile the form "skeleton". If this is the first time through the form definition process for this form with the "Call commuter module for events on this form?" button selected, this will be your only option; if, however, the commuter module may have been created (and manually modified) previously, you are also presented the option of downloading (into Windows notepad) the updated auto-generated commuter module code. You can then manually copy and paste any relevant changes from Windows notepad into your OpenInsight stored procedure.
The automatically generated 'skeleton' of the commuter module will include code for each of the events you have specified (PRE-READ, PRE-WRITE, etc.) in the form definition process. You should then add additional code to perform the desired actions during those events.
II. The O4W Form Event Model
The O4W Form, when run, may raise several different "events"; if you have created a commuter module, and choose to have those events passed to your commuter module, you may programmatically alter how O4W behaves.
When the event is raised, and the commuter module is called, it will be passed the name of the control (if applicable) that is generating the event, and the type of event. There are also several "named common" elements that you may access in your commuter module for additional flexibility. These elements include formDef@ (the definition of this O4W form), @ID (if applicable), @RECORD (if applicable), FormName@ (the name of this O4W Form), bIsNew@ (set to "1" during READ processing if this is a new record), and UserFields@ (set to the value(s) of any user defined field(s) during WRITE processing, and also set during processing of the "POPUP" event).
The commuter module 'skeleton' will also contain code to extract the name of the field that is generating the event (if applicable), and its current value (again, if applicable).
When returning from the commuter module to the O4W Form, the variable "rtnValue" must be set properly to allow, or prevent, the standard form operation for that event from occurring. Set the rtnValue to "1" to allow the event to continue processing (the default behavior), or "0" to halt that event (note that in certain circumstances described below, rtnValue may also be set to "-1" for special operations). There are also additional "named common" elements that may be set to effect the O4W Form. These elements include statMsg@ (set to have the O4W Form display a message), redirectTo@ (set after WRITE or DELETE processing to redirect the browser page), and UserFields@ (set to the value(s) of any user defined field(s) during READ processing, and also set during processing of the "POPUP" event).
III. The O4W Form Events
The events that are raised, and that may be handled through the commuter module, include:
Form level events:
- PRE_READ
- POST_READ
- READ_CHECK
- PRE_WRITE
- POST_WRITE
- PRE_DELETE
- POST_DELETE
- SELECT
- TAB
Field level events:
- PRE_FIELD
- POST_FIELD
- CLICK
- POPUP (O4W 1.1+)
The PRE_READ Event
The PRE_READ event is raised before the O4W Form reads a data record. It is called during two different processes - if there is a 'picklist', or list of possibly matching records returned as the result of a search, the PRE_READ event is raised for EACH record that is displayed in the list of records. In addition, it is called to read the actual data record that is to be displayed or edited in the main body of the form. If the "Add New" button has been pressed, then bIsNew@ is set to "1".
The commuter module code may examine either @ID, or the passed "CtlEntId" parameter, for the name of the record. The code may also set the UserFields@ variable to define 'default values' for any user-defined fields.
To continue normal processing, set rtnValue to "1". To abort the read event, set rtnValue to "0" (and optionally set statMsg@ to indicate the reason for the abort). If you wish to perform the same function as the READ event in the commuter module, set the @RECORD variable as desired, and then set rtnValue to "-1" (this instructs the O4W Form that you wish to skip the actual READ, but wish to continue normal processing beyond that).
If for example you want to read records for a specific user your code in the PRE_READ event could be as follows:
USERNO = "X_UNKOWN_X"
@RECORD = ""
OPEN 'WEB_USERS' TO USER.FL Else
statMsg@ = "Unable to access WEB_USERS table"
rtnValue=0
Return rtnValue
End
OPEN 'REVCONT' TO REVCONT.FL Else
statMsg@ = "Unable to access REVCONT table"
rtnValue=0
Return rtnValue
End
TEMPID = O4WCookie("USERID")
READ TEMP.INFO FROM O4WTEMPFILE%, TEMPID Then
READ USER.ITEM FROM USER.FL, TEMP.INFO<1> Then
READ MOEREC FROM REVCONT.FL,USER.ITEM<5> THEN
USERNO=MOEREC<1>
sno_user = Xlate("SERIALNO_HISTORY", CTLENTID, 2, "X")
If USERNO # SNO_USER Then
statMsg@="Serial number requested is not for your user ID, please call Revelation Software at (800) 262-4747."
rtnValue=0
Return rtnValue
End
End
End
End
The POST_READ Event
The POST_READ event is raised after the O4W Form reads a data record. It is called after the actual data record that is to be displayed or edited in the main body of the form has been read.
The commuter module code may examine either @ID, or the passed "CtlEntId" parameter, for the name of the record, and @RECORD for the contents of the data record. The code may also set the UserFields@ variable to define 'default values' for any user-defined fields.
The READ_CHECK Event
The READ_CHECK event is raised before a DELETE or WRITE of the record. It is done as part of the "optimistic locking" algorithm, which seeks to verify that the record has not been changed by another user during web-based processing. Before writing or deleting the record, the original record is re-read, and - if it has not been changed - the record is locked and then updated or deleted. The READ_CHECK event is raised so that the commuter module can recreate any operations performed during the original PRE_READ event (note that this event is automatically added if the PRE_READ event has been selected).
The commuter module code may examine either @ID, or the passed "CtlEntId" parameter, for the name of the record.
To continue normal processing, set rtnValue to "1". If you wish to perform the same function as the READ event in the commuter module, set the @RECORD variable as desired, and then set rtnValue to "-1" (this instructs the O4W Form that you wish to skip the actual READ, but wish to continue normal processing beyond that). Note there is no option to "abort" the READ_CHECK operation by setting rtnValue to "0" - if you wish to abort WRITE or DELETE processing, you must handle that in the PRE_WRITE or PRE_DELETE event, as appropriate.
The PRE_WRITE and PRE_DELETE Events
The PRE_WRITE and PRE_DELETE events are raised before the O4W Form writes or deletes the data record, respectively.
The commuter module code may examine either @ID, or the passed "CtlEntId" parameter, for the name of the record. The @RECORD variable will contain the updated values that are to be written or deleted. If defined, any user-defined field values will be set in the UserFields@ variable.
To continue normal processing, set rtnValue to "1". To abort the write or delete event, set rtnValue to "0" or "-1"(and optionally set statMsg@ to indicate the reason for the abort). If set to "-1", the O4W Form will return to the main entry/selection page; if set to "0", the current page remains unchanged.
The POST_WRITE and POST_DELETE Events
The POST_WRITE and POST_DELETE events are raised after the O4W Form successfully writes or deletes the data record, respectively.
The commuter module code may examine either @ID, or the passed "CtlEntId" parameter, for the name of the record. The @RECORD variable will contain the updated values that have been written or deleted. If defined, any user-defined field values will be set in the UserFields@ variable.
Optionally set statMsg@ to any message you wish to display. Optionally set redirectTo@ to the URL of any page you wish to transfer to; if not specified, the O4W Form will return to the main entry/selection page. Note that the value of the rtnValue variable is not applicable here.
The SELECT Event
The SELECT event is raised when generating the list of keys to choose from in a "picklist" type O4W Form, or when generating the search results in a "search" O4W Form.
The commuter module code may examine the passed "CtlEntId" parameter for the name of the list record that is to be created. The list record is an entry in the SYSLISTS table that contains a list of all the IDs that the user can select from.
If rtnValue is set to "1", normal processing continues. If rtnValue is set to "0", NO records are selected. If rtnValue is set to "-1", the O4W Form will proceed with whatever keys have been placed into the list record without using its own algorithm to select the keys. In this way, the commuter module can use its own logic, overriding the built-in O4W Form search/selection logic.
For example if you wanted to change the sort order of your “picklist” you can insert the following code on the SELECT event:
cmd = "SELECT ROYSCHED BY TITLE_ID BY LORANGE"
Call Rlist(cmd, 4, CtlEntId)
rtnValue = -1
The TAB Event
The TAB event is raised when the user clicks on any tab of the O4W Form, or uses the optional Back or Next buttons to navigate through the tabs.
The commuter module code may examine the passed "CtlEntId" parameter for the number of the current tab, and the UserFields@ variable for the number of the tab the user wishes to move to. Note that the commuter module 'skeleton' code will translate the current tab number into a tab name, available in the variable "tabname".
If rtnValue is set to "1", normal processing continues. If rtnValue is set to "0", the request to switch tabs is aborted; any message stored in statMsg@ will be displayed.
The PRE_FIELD Event
The PRE_FIELD event is raised when the specified field is about to get the "focus" on the web page.
The commuter module code may examine the passed "CtlEntId" parameter for the name of the web page input control that is about to get the focus. Note that the commuter module 'skeleton' code will translate the web page input control name into the name of the field as specified in the O4W form definition, available in the variable "fieldName".
If statMsg@ is set, its contents are displayed. Note that the value of the rtnValue variable is not applicable here.
The POST_FIELD Event
The POST_FIELD event is raised when the specified field is about to lose the "focus" on the web page.
The commuter module code may examine the passed "CtlEntId" parameter for the name of the web page input control that is about to lose the focus. Note that the commuter module 'skeleton' code will translate the web page input control name into the name of the field as specified in the O4W form definition, available in the variable "fieldName". In addition, the current value of the field is available in the variable "currValue".
If statMsg@ is set, its contents are displayed. If rtnValue is set to "0", focus is re-set back to this field (so the user is unable to exit this input control). Note that MANY users find this action extremely annoying, and it should thus be used only when absolutely required.
Never set the statMsg@ and rtnValue = -1. This generates an infinite loop (since the post_field is triggered by the ‘lost focus’ event, and you get into a loop where the form loses focus, you go into the commuter module, you set rtnValue = -1 (which sets us back to that same field), then you set statMsg@ (which puts up a message box)…which maes us lose focus on the field – and son on).
The CLICK Event
The CLICK event is raised when either the specified user-defined button is clicked, or the specified "dummy" popup button is clicked.
The commuter module code may examine the passed "CtlEntId" parameter for the name of the web page button that has been pressed. Note that the commuter module 'skeleton' code will translate the web page input control name into the name of the field as specified in the O4W form definition, available in the variable "fieldName". The variable "clickType" will also be set, either to "CLICK" (for a user-defined button) or "POPUP" (for a "dummy" popup button).
Note that the values of the rtnValue and statMsg@ variables are not applicable here.
The POPUP Event
The POPUP event (available in O4W 1.1 and above) is raised when specified "popup" field has returned a value.
The commuter module code may examine the passed "CtlEntId" parameter for the name of the web page button that is associated with this popup. Note that the commuter module 'skeleton' code will translate the web page input control name into the name of the field as specified in the O4W form definition, available in the variable "fieldName". The userFields@ variable will contain the return value from the popup.
The commuter module can change what value is placed into the associated field by changing the value of the userFields@ variable. The field where the popup value is to be placed can also be changed by changing the value of the "CtlEntId" variable.
If statMsg@ is not null, any text specified in statMsg@ is displayed. If rtnValue is set to "1", normal processing continues. If rtnValue is set to "0", the returned value from the popup is NOT placed in the associated field.
IV. OpenInsight Field Names and Web Form Input Controls
Once the commuter module has been invoked for a particular event, it most likely will need to access, and potentially update, elements of the browser page.
When the O4W Form was defined, fields from the specific table's dictionary, and any user-defined fields, were selected for use as "input" controls (textboxes, password boxes, etc.). When the form is actually created for the web browser, each input control is given a unique name. These names are NOT based on the "real" OpenInsight field name; rather they are based on the _location_ of the given field in the O4W Form definition.
For example, if there are 5 fields (FIRST_NAME, LAST_NAME, CITY, STATE, and ZIP) that are defined in an O4W Form named "SAMPLE", there may be 5 textboxes on the web form that is generated from SAMPLE. These 5 textboxes are named FIELD_1, FIELD_2, FIELD_3, FIELD_4, and FIELD_5. The contents of FIELD_1 are associated with the FIRST_NAME field; the contents of FIELD_2, with the LAST_NAME field; and so on.
The commuter module utility function O4WCommuterUtility has been developed to provide the "conversions" from field names to web form elements. To find which field name is associated with the current input control, we might have code like the following:
MyControlName = O4WCommuterUtility(CtlEntId, O4WUTILITY_FIELDNAME$)
To find what input control name is used for a particular field name, we need to determine the location of that field name in the list of all field names used by the form. To find the input control name for the field named "STATE", for example, we could use the following code:
stateElement = O4WCommuterUtility(CtlEntId, O4WUTILITY_FORMELEMENT_CONTROL$, "STATE")
An additional complication is multivalue fields, and associated multivalue sets that may increase or decrease in number. The O4WCommuterUtility will use the information passed in with the current control (via the parameter CtlEntId) to determine the proper value to extract from the current field:
currValue = O4WCommuterUtility(CtlEntId, O4WUTILITY_VALUE$)
If you wish to extract information from another field, simply specify that field name:
otherValue = O4WCommuterUtility(CtlEntId, O4WUTILITY_VALUE$, "STATE")
If the additional field (in this case, "STATE") is part of a multivalue association with the current field, or neither the current field nor the additional field are multivalued, you should pass in the CtlEntId variable as the first parameter; however, if the current field is multivalued and the additional field is not multivalued, or the two fields are part of different associations, you should pass in a null string ("") for the first parameter to prevent the incorrect value from being retrieved.
You can also use O4WCommuterUtility to return the names of other web page elements that you might wish to manipulate. The O4W Form is laid out as a set of 'grids', or tables of elements; each element of the table is called a "cell", and can have specific properties defined (like background color, alignment, etc.). Each field on the O4W Form consists of a label and one (or more, for multivalued data) "input controls", each in their own cells; within the cells, the contents are defined within a "section" that contains the actual text or control. Depending on what you wish to change, you can access:
- The "cell" of the grid that contains the label, with the O4WUTILITY_FORMELEMENT_LABEL¬_CELL$ parameter;
- The "cell" of the grid that contains the input control, with the O4WUTILITY_FORMELEMENT_CONTROL_CELL$ parameter;
- The "section" within the label's cell where the actual label text is defined, with the O4WUTILITY_FORMELEMENT_LABEL_SECTION$ parameter;
- The "section" within the input control's cell where the actual input control is defined, with the O4WUTILITY_FORMELEMENT_CONTROL_SECTION$ parameter;
- The input control itself, with the O4WUTILITY_FORMELEMENT_CONTROL$ parameter
V. Example Code
The following code was generated as the "skeleton" commuter module for an O4W Form named "CUSTOMER". The Pre-read, Post-write, and Tab form-level events have been selected, and there are a number of field-level events (including Pre-field and Post-field on a number of fields, a "dummy" popup button, and a user-defined button).
FUNCTION CUSTOMER_O4W_COMMUTER_MODULE(CtlEntId, Event, Request)
* Auto-generated by O4W_DEFINE_FORM at 10:51:51 06 JAN 2010
* Standard equates
$Insert O4WEquates
$Insert O4WFormEquates
$Insert O4W_COMMUTER_COMMON
rtnValue = 1
Begin Case
Case event _eqc 'PRE_READ'
* called before reading record from table
* variable 'ctlentid' is ID of record
* variable '@record' is the record contents (if available)
* variable 'userFields@' contains the values of the user-defined fields (if available)
* examine variable bIsNew@ to determine if this is a new record, or a record that is supposed to exist
* set variable 'rtnValue' to 0 (rtnValue=0)to disable further event processing
* set variable 'rtnValue' to -1 (rtnValue=-1) to skip READ but continue processing
* (If performing the read in this code, and you intend to set the rtnValue=-1, you should:
* - fill the @RECORD variable with the desired record contents
* - fill the userFields@ variable with the desired values for the user-defined fields
* )
* set variable 'statMsg@' to desired error/status text
Case event _eqc 'READ_CHECK'
* called before write or delete to verify record has not been changed by another user
* set variable 'rtnValue' to -1 (rtnValue=-1) to skip READ but continue processing
* (If performing the read in this code, and you intend to set the rtnValue=-1, you should fill the
* @RECORD variable with the desired record contents)
Case event _eqc 'POST_WRITE'
* called after writing record to table
* variable 'ctlentid' is ID of record
* variable '@record' is the record contents (if available)
* variable 'userFields@' contains the values of the user-defined fields (if available)
* set variable 'statMsg@' to any desired 'success' message
* set variable 'redirectTo@' to url to transfer to after success
Case event _eqc 'TAB'
* called when 'tab' clicked, or back/next button clicked
* variable 'ctlentid' is number of current tab
tabname = formDef@<tabnames$, ctlentid>
* variable userFields@ is number of 'next' tab
* set variable 'rtnValue' to 0 (rtnValue=0) to abort tab change
* set variable 'statMsg@' to any desired error/status text
* to examine all the fields on the current tab:
num.fields = dcount(formDef@<attr$>, @VM)
for each.field = 1 to num.fields
if formDef@<ValueTab$, each.field> = tabname then
fieldName = formDef@<attr$, each.field>
thisValue = O4WGetValue('FIELD_':each.field)
end
next each.field
Case Event _eqc 'PRE_FIELD'
* called when specified field has gotten 'focus'
fieldName = O4WCommuterUtility(CtlEntId, O4WUTILITY_FIELDNAME$)
Begin Case
Case fieldName _eqc 'WEBSITE'
End Case
Case Event _eqc 'POST_FIELD'
* called when specified field has 'lost focus'
fieldName = O4WCommuterUtility(CtlEntId, O4WUTILITY_FIELDNAME$)
currValue = O4WCommuterUtility(CtlEntId, O4WUTILITY_VALUE$)
Begin Case
Case fieldName _eqc 'WEBSITE'
Case fieldName _eqc 'ADDRESS1'
Case fieldName _eqc 'CITY'
End Case
Case Event _eqc 'CLICK'
* called when user-defined or 'dummy' popup button clicked
fieldName = O4WCommuterUtility(CtlEntId, O4WUTILITY_FIELDNAME$)
clickType = O4WCommuterUtility(CtlEntId, O4WUTILITY_CONTROLTYPE$)
Begin Case
Case fieldName _eqc 'GROUP'
* called from clicking 'popup' button
Case fieldName _eqc 'SampleBtn'
* called from clicking user-defined button
End Case
End Case
Return rtnValue
This is the code that is built by O4W without any modification. At this point, the code can be modified (using both "regular" BASIC+ programming code, and/or O4W APIs).
Example 1: Setting A Field's Value Based On Another Field
Let us suppose, for example, that we have an OpenInsight stored procedure that, when given the name of the city, can tell us the state that city is in. Let us set our STATE field's value based on the value of CITY. When the CITY field has lost "focus", we can populate the STATE field with our calculated result.
Therefore, in the "POST_FIELD" section of the skeleton code, we look for the 'CITY' case. We can add the following code:
Call FindStateFromCity(currValue, ourState)
* Determine the web form's "input element" name for the STATE field
stField = O4WCommuterUtility(CtlEntId, O4WUTILITY_FORMELEMENT_CONTROL$, "STATE")
* and update that element
O4WUpdate(stField, ourState, O4WResponseStyle(,'1'))
————-
Assuming the FindStateFromCity stored procedure returns (in the second parameter) the name of the state based on the city (in the first parameter), we just take the returned value and put it into the web form where the "STATE" field is.
As described above, we need to translate from the field name ("STATE") to the input control name; to do this, we use O4WCommuterUtility to find STATE's location in the list of fields.
Once we have determined the input control name, we use the O4W API call O4WUpdate to set that control's text to the value in the "ourState" variable. We use the O4WResponseStyle call to indicate that we only wish to update the text (and not the style) of the input control.
Example 2: Generating a POST-WRITE Redirect
Let us suppose that, after writing the record, we wish to display a specific message, and then transfer control to the Revelation home page (rather than back the start of the O4W Form). To achieve this, we must modify the code in the POST_WRITE case as follows:
—————-
redirectTo@ = "http://www.revelation.com"
statMsg@ = "Thank you for updating this record! You will now be redirected to the Revelation Home Page…"
—————-
Example 3: Aborting Form Read
As an example, perhaps we wish to forbid reading of records on the same day they were created. In the Pre-read event, we can check if the requested record is 'forbidden', and if it is, abort the read (with an appropriate error message). To achieve this, in the PRE_READ case, we can add the following code:
—————-
if bIsNew@ <> "1" then
* Not a new record - find out its creation date
createDate = xlate("CUSTOMER", @ID, 27, "X")
If createDate = DATE() Then
rtnValue = 0
statMsg@ = "Invalid record requested; not yet posted"
End
End
—————-
Example 4: Acting On A User-Defined Button
To display a static message (using the O4WError API call) when a user-defined button is clicked, we can add the following code to the "SampleBtn" case:
—————-
O4WError("This button intentionally left blank")
—————-
Example 5: Updating A ListBox
To update a more complex control, like a listbox, defined as the "input control" for another field, we must first derive the "descriptions" and their associated "code values" that will be placed in the list box. We must then replace the list box control contents entirely; we do that by actually replacing the "section" where that control is located. For example, if we wished to populate a list box in the "ADDRESS2" field when we exit the "ADDRESS1" field, we can add the following code to the "ADDRESS1" case in the "POST_FIELD" section:
—————-
* Change the 'address2' list box
Call findSubAddress(currValue, DESCS, CODES)
add2Control = O4WCommuterUtility(CtlEntId, O4WUTILITY_FORMELEMENT_CONTROL$, "ADDRESS2")
add2Section = O4WCommuterUtility(CtlEntId, O4WUTILITY_FORMELEMENT_CONTROL_SECTION$, "ADDRESS2")
o4wSectionStart(add2Section, O4WResponseStyle())
O4WListbox(DESCS, CODES, add2Control)
O4WSectionEnd(add2Section)
—————-
Assuming the findSubAddress stored procedure returns (in the second and third parameters) a list of descriptions (@VM delimited), and their associated code values, for the secondary address based on the primary address (in the first parameter), we can take the returned values and put them into the web form where the "ADDRESS2" field is.
As described above, we need to translate from the field name ("ADDRESS2") to the input control name; to do this, we use O4WCommuterUtility to find ADDRESS2's location in the list of fields. We also use O4WCommuterUtility to retrieve the name of the "section" where ADDRESS2's input control is located.
Once we have determined the input control name, and the section where it is defined, we use the O4W API calls O4WSectionStart, O4WListBox, and O4WSectionEnd to effectively recreate that very small section of the browser's page. The O4WResponseStyle modifier, invoked with no parameters, indicates that we will be replacing the entire element (text, style, attributes, etc.). Once we have recreated the section, we create the new list box, and our new descriptions are now available.
Completed, Modified Commuter Module
FUNCTION CUSTOMER_O4W_COMMUTER_MODULE(CtlEntId, Event, Request)
* Auto-generated by O4W_DEFINE_FORM at 10:51:51 06 JAN 2010
* Standard equates
$Insert O4WEquates
$Insert O4WFormEquates
$Insert O4W_COMMUTER_COMMON
rtnValue = 1
Begin Case
Case event _eqc 'PRE_READ'
* called before reading record from table
* variable 'ctlentid' is ID of record
* variable '@record' is the record contents (if available)
* variable 'userFields@' contains the values of the user-defined fields (if available)
* examine variable bIsNew@ to determine if this is a new record, or a record that is supposed to exist
* set variable 'rtnValue' to 0 (rtnValue=0)to disable further event processing
* set variable 'rtnValue' to -1 (rtnValue=-1) to skip READ but continue processing
* (If performing the read in this code, and you intend to set the rtnValue=-1, you should:
* - fill the @RECORD variable with the desired record contents
* - fill the userFields@ variable with the desired values for the user-defined fields
* )
* set variable 'statMsg@' to desired error/status text
if bIsNew@ <> "1" then
* Not a new record - find out its creation date
createDate = xlate("CUSTOMER", @ID, 27, "X")
If createDate = DATE() Then
rtnValue = 0
statMsg@ = "Invalid record requested; not yet posted"
End
End
Case event _eqc 'READ_CHECK'
* called before write or delete to verify record has not been changed by another user
* set variable 'rtnValue' to -1 (rtnValue=-1) to skip READ but continue processing
* (If performing the read in this code, and you intend to set the rtnValue=-1, you should fill the
* @RECORD variable with the desired record contents)
Case event _eqc 'POST_WRITE'
* called after writing record to table
* variable 'ctlentid' is ID of record
* variable '@record' is the record contents (if available)
* variable 'userFields@' contains the values of the user-defined fields (if available)
* set variable 'statMsg@' to any desired 'success' message
* set variable 'redirectTo@' to url to transfer to after success
redirectTo@ = "http://www.revelation.com"
statMsg@ = "Thank you for updating this record! You will now be redirected to the Revelation Home Page…"
Case event _eqc 'TAB'
* called when 'tab' clicked, or back/next button clicked
* variable 'ctlentid' is number of current tab
tabname = formDef@<tabnames$, ctlentid>
* variable userFields@ is number of 'next' tab
* set variable 'rtnValue' to 0 (rtnValue=0) to abort tab change
* set variable 'statMsg@' to any desired error/status text
* to examine all the fields on the current tab:
num.fields = dcount(formDef@<attr$>, @VM)
for each.field = 1 to num.fields
if formDef@<ValueTab$, each.field> = tabname then
fieldName = formDef@<attr$, each.field>
thisValue = O4WGetValue('FIELD_':each.field)
end
next each.field
Case Event _eqc 'PRE_FIELD'
* called when specified field has gotten 'focus'
fieldName = O4WCommuterUtility(CtlEntId, O4WUTILITY_FIELDNAME$)
Begin Case
Case fieldName _eqc 'WEBSITE'
End Case
Case Event _eqc 'POST_FIELD'
* called when specified field has 'lost focus'
fieldName = O4WCommuterUtility(CtlEntId, O4WUTILITY_FIELDNAME$)
currValue = O4WCommuterUtility(CtlEntId, O4WUTILITY_VALUE$)
Begin Case
Case fieldName _eqc 'WEBSITE'
Case fieldName _eqc 'ADDRESS1'
* Change the 'address2' list box
Call findSubAddress(currValue, DESCS, CODES)
add2Control = O4WCommuterUtility(CtlEntId, O4WUTILITY_FORMELEMENT_CONTROL$, "ADDRESS2")
add2Section = O4WCommuterUtility(CtlEntId, O4WUTILITY_FORMELEMENT_CONTROL_SECTION$, "ADDRESS2")
o4wSectionStart(add2Section, O4WResponseStyle())
O4WListbox(DESCS, CODES, add2Control)
O4WSectionEnd(add2Section)
Case fieldName _eqc 'CITY'
Call FindStateFromCity(currValue, ourState)
* Determine the web form's "input element" name for the STATE field
stField = O4WCommuterUtility(CtlEntId, O4WUTILITY_FORMELEMENT_CONTROL$, "STATE")
O4WUpdate(stField, ourState, O4WResponseStyle(
,'1'))
End Case
Case Event _eqc 'CLICK'
* called when user-defined or 'dummy' popup button clicked
fieldName = O4WCommuterUtility(CtlEntId, O4WUTILITY_FIELDNAME$)
clickType = O4WCommuterUtility(CtlEntId, O4WUTILITY_CONTROLTYPE$)
Begin Case
Case fieldName _eqc 'GROUP'
* called from clicking 'popup' button
Case fieldName _eqc 'SampleBtn'
* called from clicking user-defined button
O4WError("This button intentionally left blank")
End Case
End Case
Return rtnValue