=====================================================================
Form in a Form in a Form in a Form
=====================================================================
PRODUCT: R:BASE VERSION: 4.5
=====================================================================
AREA: FORMS CATALOG: FORMS, REPORTS & LABELS
=====================================================================
One of the exciting new features of R:BASE 4.5 is the ability to call
a form from within an Entry/Exit procedure. The called form can be
used to either add or edit data. This allows developers, even
beginning users to increase the flexibility and ease of use for a
standard form. When you use this feature with the new row and table
level Entry/Exit procedures the possibilities are almost endless.
This article presents some ideas and ways to use the form in a form
feature, but also describes some of the areas that cause more
headaches than results. Is this a complete listing of things to do or
avoid?, no, this is merely a beginning. Look for more ways to use form
in a form in future issues of the Exchange.
It's simple to set up a form in a form. Just write an Entry/Exit
procedure using R:BEDIT or your favorite ASCII text editor. Include
either ENTER formname or EDIT USING formname, any of the command
options can be used. A simple Entry/Exit procedure to do a form in a
form requires just the following commands:
SET ERROR MESSAGES OFF
SET MESSAGES OFF
ENTER tranform
RETURN
It really is this simple. When this runs it will place you into the
form Tranform in the Add data mode. There is no error checking being
done and the form in a form will always execute. The EEP can be placed
as an entry or exit EEP on a field through the field settings screen
or as a row or table level EEP through the table settings screen.
Be aware that you will not be able to modify the same row of data in
the same table using a form in a form. You cannot enter a new row then
edit that row in a secondary form. You cannot edit or add parts of the
same row in a form in a form. You must always return to the outer form
and it will resave the row over edits made in the inner form. A form
in a form can reference other rows from the same table, just not the
same row.
Most of the time the form in a form has some type of connection to the
first form. The easiest type of connection between the two forms is
using a variable to link the forms. Remember, the form in a form is
called from an EEP, an EEP doesn't know about column values, only
about variable values. In both forms, locate the same variable name.
The data would appear and be loaded to the tables in both forms using
ENTER. You also need an expression in both forms like this to save the
variable data into a column in each table:
Column_name = .variable_name
This loads the variable value into the column, and the link between
the tables is created. When EDITing data, use the command EDIT USING
formname WHERE column_name=.variable_name. The brings up a matching
row of data in the form in a form. Again, a fairly simple process to
link a form in a form. A few things to remember:
1. The column in the expression should be a linking column
between the tables (has the same name). This makes sure the
link will also work if the tables are used in a multi-table
form.
2. The expression is required or when you exit from the forms
the variable data will not be saved to the tables.
3. Don't modify the same row of data in the same table in a form
in a form.
4. Call the Entry/exit procedure after you have entered the data
into the variable. It can be a field level EEP on the
variable, or a row level EEP called after leaving the row.
Now, suppose the first table has an autonumbered column and that
column is the link between the two forms (i.e. tables). The same type
of setup is used with one exception. The first form, instead of an
expression that says Column_name = .variable_name, has one that is
just the opposite. The expression would be:
variable_name = Column_name
What happens is, when the first form starts up, the autonumber column
increments, and variable list is evaluated. The new number moves from
the column (which is placed as a field on the form) into the variable.
Then the form in a form picks up that variable value. When second form
is exited, the number from the variable (the autonumber) is saved to
the column and the tables are linked. Multiple rows can be entered in
the form in a form, each of the rows is linked to the same row in the
first form.
Now that the process is clear, look at some real examples.
Example 1: Set up a transaction form where you can edit the customer
information for existing customers or add a new customer record if the
customer is not yet on file. This example uses the Concomp sample
database and is based on the form tranform. The first thing is to make
a copy of tranform. The copy will be modified to use a form in a form.
1. Replace the custid field in the Transmaster table with the
variable vcustid
2. Add an expression to the Transmaster table, custid = .vcustid.
3. Modify the lookup expression in the Customer table so that the
WHERE clause reads WHERE custid = .vcustid.
4. Add the following Entry/Exit procedure, custform.cmd, as an
Exit procedure on the vcustid field in the Transmaster table.
5. Create a quick form, named cform, based on the Customer table
6. Add an expression to cform, vcustid = custid.
7. Using RBEDIT create the file called custform.cmd.
*( The Exit Procedure custform.cmd )
SET ERROR MESSAGES OFF
SET MESSAGES OFF
DEBUG SET ERROR MESSAGES ON *( FOR DEBUGGING )
DEBUG SET MESSAGES ON
DEBUG TRACE
SET ERROR VARIABLE verror
DIALOG 'Verify Existence of customer?' RKEY EKEY YES
IF EKEY = 'NO' THEN
RETURN
ELSE
EDIT USING cform WHERE custid = .vcustid
SET VAR vexist = .verror
IF vexist <> 0 THEN
ENTER cform
ENDIF
ENDIF
RECALC
RETURN
Place this as an Exit procedure on the Field settings screen for
vcustid. After the user enters the customer id value into the
variable vcustid he will be asked if he wants to verify the id. number
(The DIALOG command). The Exit procedure then tries to edit data using
the vcustid value the user entered. If the edit fails the error
variable is set to a non-zero value, and the procedure then brings up
the form cform for entering new customer information. The custid
column in the Customer table is an autonumber column so it will
automatically increment. As the user leaves cform, the variable is set
equal to the column, so when you return to tranform, the Customer
table lookup will access the correct data, either the edited
information or the new information. This an easy way to verify that
the customer information is correct or to add new customer
information.
Example 2: Allow users to lookup rows of data to edit from within a
form. Previous versions of R:BASE required a command file that took
you in and out of the edit form. Using form in a form lets you sit in
a field in a form and enter different values for which the row or rows
immediately appear for editing. Edit the data, save changes and the
cursor returns to the same field on the form ready for entry of the
next data value to lookup and edit. You can easily modify your
existing edit forms to do this.
1. Make a copy of the form. The copy of the original form is used
as a "template".
2. Modify the copy. Remove all field locations for the first
table in the form. Remove all tables except for the first
table (automatically removes the field locations for those
tables). Remove all pages except the first page (automatically
removed when all field locations are removed.
3. On the Form settings screen, indicate this form can only be
used with edit. Remove the menu from the form.
4. You now have a "template", a form that looks like the first
page of the original form, but with no fields located and no
user-defined menu. The actual editing of data is done on the
original form.
5. Locate a variable in the same position as the field that is
used as the lookup or search field. For example, if you edit
customer records and identify customers by the Cust_Id column,
locate a variable, VCust_Id, in the same location on the form
where the Cust_Id column is located on the original form.
6. Customize the Field settings for the variable to make sure the
user can change the data in the field.
7. Add the following Entry/Exit procedure, search.eep, as an Exit
procedure on the variable field.
8. Using RBEDIT create the file called search.eep.
*( The Exit Procedure search.eep )
SET VAR vlast = (lastkey(0))
IF vlast = '[Esc]' THEN
RETURN
ENDIF
EDIT USING original_form WHERE Cust_Id = .VCust_Id
SET VARIABLE VCust_Id = NULL
RETURN
The procedure will execute unless the user presses [Esc] from the
template form. If the user presses [Esc] the procedure does not
execute and they exit the template form. The EDIT USING command brings
up the original form using a WHERE clause with the VCust_Id variable
identifying the specified customer. After the data is edited and the
original form exited, the variable VCust_Id is reset to NULL so it
will be blank on return to the template form.
The template form could be further customized to use a pop-up menu for
the VCust_Id field. Users can select the correct customer from a menu
displaying the id and the name. The EEP and the form in a form stay
the same.
What else can you do with a form in a form? You are not limited to
calling just one form. That form can call another form and so on. The
number of forms you can nest is limited by available memory. When you
reach the limit R:BASE will give you a message and you need to then
back out of each form. Use a form in a form to Enter/Edit a form at a
specific screen row to emulate windowed forms. A form in a form can
display historical data at the press of a key. Allow users to view
data in any table in the database using form in a form. You could
potentially run your entire application from a form. The possibilities
are endless. Just remember that a form in a form needs to reference a
different table or different rows of data if the table is the same.