Create a header-detail construction
by Frank G. Vandervelpen
Frank has written some general guidelines on creating a basic header-detail construction in VDF
|No Files Available
||Frank G. Vandervelpen
||Velpe Development bvba
A lot of items relate from a child file to a parent file.
They typically appear as an order, invoice, delivery note or delivery addresses for a customer. The view is often defined as a section for the header and a table for each child record.
Let's call the Header table INVHEAD and the detail table INVLINE
We need the dd's of both the header and detail table.
We will constrain the detail to the header
In the dd-object of the INVLINE in the view we add.
Set Constrain_File to INVHEAD.File_Number
This will give us the ability to view only the data in the INVLINE that corresponds to the active record.
Tip: You can dynamically change your constraints through the method «Rebuild_Constraints»
The view is build in this way
odd's (ģ ģ )
odbForms (ģ ģ )
The server and the Main_dd are the ones that are associated with the header table
However the controlling of the detail should be through the detail file. We will change in the odbGrid the following:
Set Main_File to INVLINE.File_Number
Set Server to INVLINE_DD(Current_Object))
This makes the save pass through the dd of the detail data dictionary.
When we have such a view, we want to have a valid existing header record before entering the detail records...
To have this behaviour we should do some coding.
Set Child_Table_State to True
If this property is true, the entering message sends the child_entering message and the exiting message sends the child_exiting message. These additional messages are provided for tables that are children of parent (header) tables.
This gives us the ability through the child_entering message to do some testing. One of the things we want is to check whether a header exists and/or to save it.
// The following is called when entering the table. It checks with the header
// to see if it has a valid saved record. If not, entry is not allowed.
Function Child_entering returns Integer
local integer liRVal
// Check with header to see if it is saved.
Delegate Get Save_Header to liRVal
function_return liRVal // if non-zero don't enter in the detail
This should be placed in the odbGrid. There are some other methods that are added to this object for easier manipulation...
// Change: Assign insert-row key append a row Create new behavior to support append a row and to optimize the table refresh
on_Key kADD_MODE send append_a_row
// Add new record to the end of the table.
Procedure Append_a_Row // Q: how would a keyboard do this?
Send End_Of_Data // A: Go to end of table and
Send Down // down 1 line to empty line
// The way this table is set up, items can never be added out of order.
// New items are always added to the end of the table.
// By setting Auto_Regenerate_State to false we are telling the table to never bother reordering after adding records.
// This is a minor optimization.
Set Auto_Regenerate_state to false // table is always in order.
We delegated a message Save_Header to the parent objects, but we did not define it, so in the odbView we need to add this procedure that passes the value if we may enter the detail lines.
Function Save_header returns integer
Local integer liRec liChanged liSrvr
Get Server to liSrvr //The Header DDO.
Get Current_Record of liSrvr to liRec //The current order record #.
Get Should_Save to liChanged //Are there any current changes?
// If there is no record and no changes we have an error.
If (liRec=0 AND liChanged=0) Begin //no record
Error 3xx 'You must First Create or Save Header'
//Attempt to Save the current Record
//The save succeeded if there are now no changes, and we have a saved record.
//Should_save tells us if we've got changes. We must check the data-sets
//current_record property to see if we have a record. If it is 0, we had no save.
Get Should_Save to liChanged //is a save still needed
Get Current_record of liSrvr to liRec //current record of the DD
//if no record or changes still exist, return an error code of 1
If (liRec=0 OR liChanged) Function_return 1
This function will return whether the detail section can or can't be entered. These lines need to be added in the odbForm
// Change: Create custom confirmation messages for save & delete. We must create the new functions and assign verify messages to them.
Function Confirm_Delete_Order Returns Integer
local integer liRVal
Get confirm "Delete Entire Header?" to liRVal
// Only confirm on the saving of new records
Function Confirm_Save_Order Returns Integer
local integer liNoSave liSrvr liRec
Get Server to liSrvr
Get Current_Record of liSrvr to liRec
If liRec eq 0 Get Confirm "Save this NEW header?" to liNoSave
// Define alternate confirmation Messages
Set Verify_Save_MSG to GET_Confirm_save_order
Set Verify_Delete_MSG to GET_Confirm_delete_order
We can make custom save & delete messages for the header. These lines needs to be added to the odbForm
- Header Table.
- Constrain child to parent table.
- Set child_table_state to True.
- Check if you may enter the table in the odbGrid.
- Ask odbForm if you may enter.
- Make custom save and delete messages.