The following sections may contain various combinations of these objects:
Figure 1 - Component Hierarchy
|MENU||This is a screen from the standard Menu and Security System. It shows a list of options that are available to the user. Options to which the user has not been granted access will not be displayed.|
|PARENT||This is a form component which has been selected from a menu screen. This may contain a set of Navigation Buttons (a mini menu) which allows other options to be selected. Options to which the user has not been granted access will be dimmed and inoperative.|
|CHILD||This is a form component which has been selected from another form component, not from a Menu screen. A child component may have children of its own.|
The Menu and Security System uses the following code to activate any selection made by the user:-
$$component = <selection> $$instance = "" $$properties = "" $$operation = "EXEC" $$params = "" call ACTIVATE_PROC
$$component is actually the Transaction ID which is contained with the Menu database. It is usually the same as the component ID, but it can be different. Refer to Menu and Security System, Appendix E: Component Identities for more details.
$$instance is the name to be given to this instance of the component. This is usually left empty as the choice of name is decided by settings on the Menu database. Refer to Menu and Security System, Appendix D: Instance Names for more details.
$$operation is set to
EXEC so that the component instance is activated at its <EXEC> trigger rather than any custom operation.
Some components may be programmed to accept a single string parameter whereas others may not. For this reason the standard ACTIVATE_PROC uses code similar to the following to activate the instance:-
activate lv_Instance.$$operation() ; without PARAMS if ($procerror = <UPROCERR_NPARAMETERS>) ; param mismatch activate lv_Instance.$$operation($$params) ; try with endif
This first tries to activate without any parameters, but if this fails it tries a single argument which may or may not be empty. No component which is to be activated directly from a menu should therefore be programmed to accept more than a single string parameter, and should be capable of dealing with an empty string.
When running a form component the user may wish to run another form component. Navigation Buttons within the component allow the user to activate another component without having to return to a menu screen. These Navigation Buttons act as a 'mini menu'. In this situation the current component is known as the PARENT and the component to be activated is known as the CHILD.
It is also common practice for the current context to be passed down from the PARENT to the CHILD so that the CHILD form can automatically retrieve the current object without further intervention from the user. To achieve this the <detail> trigger of the Navigation Button should contain code similar to the following:-
$$component = $fieldname $$instance = "" $$properties = "" $$operation = "" call LP_PRIMARY_KEY call ACTIVATE_PROC
You should have noticed that this uses the same ACTIVATE_PROC that was described in the previous section.
The local proc LP_PRIMARY_KEY is used to fill global variable
$$PARAMS with the current context. It contains code similar to the following:-
entry LP_PRIMARY_KEY ; load parameter to pass to child process $$params = $keyfields(<MAIN>,1) ; load names of pkey items setocc "<MAIN>",$curocc(<MAIN>) ; make occurrence current putlistitems/id $$params ; insert representations end LP_PRIMARY_KEY
$keyfieldsfunction will turn
$$PARAMSinto an indexed list containing all those field names which constitute the primary key of the current occurrence.
putlistitems/idwill convert this indexed list into an associative list by inserting the current value of each field name in the list.
The local proc LP_PRIMARY_KEY is included in the code which is inherited from the component template and can deal with a primary key which contains any number of fields. This standard code should not require any additional action by the developer.
In order to deal with the contents of
$$PARAMS the <EXEC> trigger of the child component should contain code similar to the following:-
params string $params$ : IN endparams getlistitems/id/component $params$ ; copy to component variables clear/e "<MAIN>" getlistitems/occ $params$, "<MAIN>" retrieve/x "<MAIN>" if (!$dbocc(<MAIN>)) putmess "primary key: %%$params$" message $text(M_90007) ; no record found exit(1) endif edit
This code will be automatically inherited from the component template and may contain minor differences between one template and another. This is because each template is purpose built to deal with a particular set of circumstances and may be required to behave in a different manner.
If the child makes a modification to the database it is a good idea for the parent to be informed of what has changed so that it can update its display accordingly. This can be done with every STORE that is performed in the child rather than waiting for the child to terminate and return control to its parent. However, the passing of parameters from parent to the <exec> trigger of the child is one way only. If details need to be passed back from the child to the parent there are the following choices:
This is the most common method and has been built into the standard code for various types of form component. For example, when a form of type Add, Update or Delete has successfully modified the database it sends a message (a single string containing an associative list) to its parent which identifies the occurrence and the action taken. This message is received and processed in the <async interrupt> trigger of the parent.
The <STORE> trigger will typically contain code similar to the following:-
$$msgdata = "" ; load message for parent putlistitems/occ $$msgdata, "<MAIN>" $$msgid = "ENTRY_ADDED" call STORE_PROC
This loads the data from a modified occurrence into
$$MSGDATA as an associative list.
The global STORE_PROC contains code similar to the following:-
store if ($status < 0) message "Store failed" else if ($status = 1) message "No modifications found - store not executed" else commit if ($$msgdata != "") ; post message to parent process call POSTMESSAGE($$msgdst,$$msgid,$$msgdata) if ($procerror) call PROC_ERROR($procerrorcontext) endif endif endif endif
Provided that the
STORE is successful a message will be posted to the parent instance. This should be received and processed in the <async. interrupt> trigger of the parent using code similar to the following:-
if ($msgid = "ENTRY_ADDED") ; entry added creocc "<MAIN>",$curocc(<MAIN>)+1 getlistitems/occ/init $msgdata, "<MAIN>" ; retrieve any inner/up entities endif if ($msgid = "ENTRY_UPDATED") ; entry updated creocc "<MAIN>",$curocc(<MAIN>)+1 getlistitems/occ/init $msgdata, "<MAIN>" retrieve/o "<MAIN>" if ($status = 0) ; does not exist discard "<MAIN>" else getlistitems/occ $msgdata, "<MAIN>" endif endif if ($msgid = "ENTRY_DELETED") ; entry deleted creocc "<MAIN>",$curocc(<MAIN>)+1 getlistitems/occ/init $msgdata, "<MAIN>" retrieve/o "<MAIN>" discard "<MAIN>" endif
Note that this uses the contents of
$$MSGDATA) to make any necessary adjustments to the occurrences being displayed. It does not have to perform a
RETRIEVE to rebuild the whole display.
It is possible for a child component to perform multiple updates and therefore send multiple messages back to its parent.
If a message other than a single string needs to be passed back to the parent form then custom code similar to the following will be required:-
..... activate <instancename>.CUSTOM_OPERATION(arg1,arg2,,,,argN) .....
This will require an equivalent operation in the target component using code similar to the following:-
operation CUSTOM_OPERATION params type arg1 : IN/INOUT/OUT type arg2 : IN/INOUT/OUT ... type argN : IN/INOUT/OUT endparams ..... ..... end CUSTOM_OPERATION
As with messages it is possible for this child-to-parent communication to take place multiple times before the child is terminated.