===================================================================== 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.