Add Back and Ahead Buttons to Your Solutions
Rescue lost users-and make your programs more intuitive-by adding navigation buttons to your FileMaker Pro applications.

By Jonathan Stars

PRODUCT: This began with FileMaker Pro 4.0 but it will work with later versions. The solution is very complex and there are probably better ways to implement it. I think it serves more to prove that if you want to do something in FileMaker, you probably can.


Many users don't always understand how to use the navigation buttons on their screens. They might do something they didn't intend to, for example, and end up in the middle of Filesville-with no idea how to get back to where they were. Even the Main Menu button doesn't help. However, navigation buttons (similar to the ones used in web browsers) can be handy tools to help your users navigate your FileMaker Pro solutions. Read on to find out how to add these buttons to your applications. But keep in mind that this is a very complex solution. Since it was developed prior to FileMaker 7, these days it would probably be better to park the data that is stored in global fields as records in other tables.

Memorize your moves
What you need is a mechanism to memorize your moves through your files, layouts and records- and a way to play them back. The perfect place for the storage is in Global fields. The perfect tool to play back the moves is ScriptMaker. Before you can create the fields, you need a file. Select File > New, and name the file Home. When the Define Fields window opens, create two utility fields:

Field Name

Type

Options

"Connect"

Calculation

=1

"Record ID"

Number field

Auto-enter

     

All the other fields are Global text fields. They'll be used for navigation storage. Name them as follows:

• gFile Back
• gLayout Back
• gRecord Back
• gFile Ahead
• gLayout Ahead
• gRecord Ahead
• gGo which File
• gGo which Layout
• gGo which Record

The first of the three Global fields put down Hansel-and-Gretal-like bread crumbs, so you can retrace your steps. When you do go backward, the second three fields make sure the bread crumbs stay on the trail you're retracing. The last three bread crumbs (uh, fields) tell you exactly where you are, so the correct record, layout, and file are displayed. Exit the Define Fields mode by clicking on the Done button. Normally, you would go into the Layouts next. In this case, however, the first layout with buttons and their attached scripts will be duplicated to a second layout. So, you need to define the Scripts first.

Scripts
One of the great things about FileMaker Pro is that there are a number of ways of performing any given task. For instance, another way to do much of the scripting I'm going to show you can be accomplished using calculation fields. With Calculations, you'd still need as many script steps. Each of them would just be shorter, referring to an If calculation-but that means you wouldn't be able to see everything that's going on. I prefer using scripts because I can see exactly what's happening. Plus, I only have to go to the script to debug any problems. In ScriptMaker, create a Script called Remember Where You've Been. Now, this is going to look like a lot, but much of it is quite repetitious. (If you chicken out, you can go to http://www. advisor.com and download a copy of the files). Enter the following steps (I'll explain what's happening afterward):

Script Name: Remember Where You've Been
If ["not IsEmpty(gFile Ahead)"]
    Set Field ["gFile Back", "If(IsEmpty(gFile Back), Status(CurrentFileName), gFile Back & "¶" Status(CurrentFileName))"]
    Set Field ["gLayout Back", "If(IsEmpty(gLayout Back), Status(CurrentLayoutNumber), gLayout Back & "¶" & Status(CurrentLayoutNumber))"]
    Set Field ["gRecord Back", "If(IsEmpty(gRecord Back), Record ID, gRecord Back & "¶" & Record ID)"]
    Loop
       Set Field ["gFile Back", "gFile Back &"¶" & Right(gFile Ahead, Length(gFile Ahead) - Position(gFile Ahead, "¶", 1, PatternCount(gFile Ahead, "¶")))"]
       Set Field ["gLayout Back", "gLayout Back &"¶" & Right(gLayout Ahead, Length(gLayout Ahead) -Position(gLayout Ahead, "¶", 1, PatternCount(gLayout Ahead,"¶")))"]
       Set Field ["gRecord Back", "gRecord Back &"¶" & Right(gRecord Ahead, Length(gRecord Ahead) -Position(gRecord Ahead, "¶", 1, PatternCount(gRecord Ahead,"¶")))"]
       Set Field ["gFile Ahead", "Left(gFile Ahead, Position(gFile Ahead, "¶", 1, PatternCount(gFile Ahead "¶"))-1)"]
       Set Field ["gLayout Ahead", "Left(gLayout Ahead, Position(gLayout Ahead, "¶", 1, PatternCount(gLayout Ahead,"¶"))-1)"]
       Set Field ["gRecord Ahead", "Left(gRecord Ahead, Position(gRecord Ahead, "¶", 1, PatternCount(gRecord Ahead,"¶"))-1)"]
        Exit Loop If ["IsEmpty(gLayout Ahead)"]
    End Loop
    Else
    Set Field ["gFile Back", "If(IsEmpty(gFile Back), Status(CurrentFileName), gFile Back & "¶" &Status(CurrentFileName))"]
    Set Field ["gLayout Back", "If(IsEmpty(gLayout Back), Status(CurrentLayoutNumber), gLayout Back & "¶" & Status(CurrentLayoutNumber))"]
    Set Field ["gRecord Back", "If(IsEmpty(gRecord Back), Record ID, gRecord Back & "¶" & Record ID)"] 
End If
Set Field ["gFile Ahead", """"]
Set Field ["gLayout Ahead", """"]
Set Field ["gRecord Ahead", """"]

The basic part of this script comes after the Else step. As you make a move to a different layout, record, or file, the script remembers the place you leave and puts a return between entries. Everything above the Else step is there to let you jump from anywhere in the Back and Ahead chain to a new place, while retaining all your moves since the beginning of the session. The Loop section keeps all your moves in the order they were originally in. The next five scripts only have two steps in them. The first step in each of them is:

Perform Script [Sub-scripts, "Remember where you've been"]

Here are the definitions for those scripts:

Script name: Go to Layout 1
Perform Script [Sub-scripts, "Remember where you've been"]
Go to Layout ["Layout #1"]

Script name: Go to Layout 2
Perform Script [Sub-scripts, "Remember where you've been"]
Go to Layout [original layout]

Script name: Go to next Record
Perform Script [Sub-scripts, "Remember where you've been"]
Go to Record/Request/Page [Next]

Script name: Go to previous Record
Perform Script [Sub-scripts, "Remember where you've been"]
Go to Record/Request/Page [Previous]

Script name: Go to File #2
Perform Script [Sub-scripts, "Remember where you've been"]
Perform Script [Sub-scripts, <unknown>]

You can't, however, tell the "Go to Layout 2" script to go to Layout 2 because the Layout hasn't been made yet. Plus, there's no external script to take you to the other file in "Go to File #2". Some of what follows will only be necessary so you can create these files with these layouts to literally watch how this solution works. When you do this for your own solution in existing files, these layouts and the Global fields need never be seen. The scripts will be subscripts within your own scripts attached to your buttons. As you move back and forth between the files, the Land Here script is used by the other file as a place to, well... land. For now, let the "Go to Record/Request/Page" step remain on [First]. We'll come back and change it later.

Script Name: Land Here
Go to Layout ["gGo which Layout"]
Go to Record/Request/Page [First]
Halt Script

The Clear script empties out all the navigation fields whenever the file opens, preparing for the session. You can also use it to start over when you run experiments with the file:

Script Name: Clear
Set Field ["gFile Back", """"]
Set Field ["gLayout Back", """"]
Set Field ["gRecord Back", """"]
Set Field ["gFile Ahead", """"]
Set Field ["gLayout Ahead", """"]
Set Field ["gRecord Ahead", """"]
Find All
Enter Browse Mode

Before going on to the final scripts, click on OK > Done to exit ScriptMaker. Select Edit > Preferences > Document. Look at the section in the dialog under the heading When opening "Home".

Click on the box next to Perform script. Now, click on the pop-up menu on the same line and choose the Clear script you just created.

Finally, the scripts you've all been waiting for: Back and Ahead! They're pretty lengthy. However, like the Remember Where You've Been script I showed you earlier, most of it is repetitious.

These scripts refer to a file I haven't shown you yet called Away. Because most of the scripts, layouts, and buttons will be duplicated over there, it'll be easier to refer to them now with incomplete script steps. Later, you can copy the file and make the necessary changes. The place where the changes will go are highlighted with double asterisks **. Open ScriptMaker and get started!

Script Name: Back Button

If ["not IsEmpty(gFile Back)"]
    Set Field ["gGo which File", "Right(gFile Back, Length(gFile Back) - Position(gFile Back, "¶", 1 PatternCount(gFile Back, "¶")))"]
    Set Field ["gGo which Layout", "Right(gLayout Back, Length(gLayout Back) - Position(gLayout Back, "¶", 1, PatternCount(gLayout Back, "¶")))"]
    Set Field ["gGo which Record", "Right(gRecord Back, Length(gRecord Back) - Position(gRecord Back, "¶", 1, PatternCount(gRecord Back, "¶")))"]
    Set Field ["gFile Ahead", "If(IsEmpty(gFile Ahead), Status(CurrentFileName), gFile Ahead & "¶" Status(CurrentFileName))"]
    Set Field ["gLayout Ahead", "If(IsEmpty(gLayout Ahead), Status(CurrentLayoutNumber), gLayout Ahead & "¶" & Status(CurrentLayoutNumber))"]
    Set Field ["gRecord Ahead", "If(IsEmpty(gRecord Ahead), Record ID, gRecord Ahead & "¶" & Record ID)"]
    Set Field ["gFile Back", "Left(gFile Back, Position(gFile Back, "¶", 1, PatternCount(gFile Back, "¶")) - 1)"]
    Set Field ["gLayout Back", "Left(gLayout Back, Position(gLayout Back, "¶", 1, PatternCount(gLayout Back, "¶")) - 1)"]
    Set Field ["gRecord Back", "Left(gRecord Back, Position(gRecord Back, "¶", 1, PatternCount(gRecord Back, "¶")) - 1)"]
    If ["gGo which File = "Away""]
      ** Set Field []
      ** Perform Script [Sub-scripts, <unknown>]
    End If
    Go to Layout ["gGo which Layout"]
    ** Go to Related Record []
End If

For the Back Button, the script is saying: Grab the last bread crumb, put it in the "Ahead" box, and take me to where it was lying on the path in the woods. The Ahead button does the same thing in the opposite direction. The script looks for the last line (defined by the last return) in the gFile Back, gLayout Back, and gRecord Back Global storage fields. It peels off that information and puts it in the g_Ahead set of fields. It also sends a copy to the gGo which fields, so it knows where to send you. Then, it takes you there.

Script Name: Ahead Button
If ["not IsEmpty(gFile Ahead)"]
    Set Field ["gFile Back", "If(IsEmpty(gFile Back), Right(gGo which File, Length(gGo which File) - Position(gGo which File, "¶", 1, PatternCount(gGo which File, "¶"))), gFile Back & "¶" & Right(gGo which File, Length(gGo which File) - Position(gGo which File, "¶", 1, PatternCount(gGo which File, "¶"))))"]
    Set Field ["gLayout Back", "If(IsEmpty(gLayout Back), Right(gGo which Layout, Length(gGo which Layout) -Position( gGo which Layout, "¶", 1, PatternCount(gGo which Layout, "¶"))), gLayout Back & "¶" & Right(gGo which Layout, Length(gGo which Layout) - Position(gGo which Layout, "¶", 1, PatternCount(gGo which Layout, "¶"))))"]
    Set Field ["gRecord Back", "If(IsEmpty(gRecord Back), Right(gGo which Record, Length(gGo which Record) -Position( gGo which Record, "¶", 1, PatternCount(gGo which Record, "¶"))), gRecord Back & "¶" & Right(gGo which Record, Length(gGo which Record) - Position(gGo which Record, "¶", 1, PatternCount(gGo which Record, "¶"))))"]
    Set Field ["gGo which File", "Right(gFile Ahead, Length(gFile Ahead) - Position(gFile Ahead, "¶", 1, PatternCount(gFile Ahead, "¶")))"]
    Set Field ["gGo which Layout", "Right(gLayout Ahead, Length(gLayout Ahead) - Position(gLayout Ahead, "¶", 1, PatternCount(gLayout Ahead, "¶")))"]
    Set Field ["gGo which Record", "Right(gRecord Ahead, Length(gRecord Ahead) - Position(gRecord Ahead, "¶", 1, PatternCount(gRecord Ahead, "¶")))"]
    Set Field ["gFile Ahead", "Left(gFile Ahead, Position(gFile Ahead, "¶", 1, PatternCount(gFile Ahead, "¶")) - 1)"]
    Set Field ["gLayout Ahead", "Left(gLayout Ahead, Position(gLayout Ahead, "¶", 1, PatternCount(gLayout Ahead, "¶")) - 1)"]
    Set Field ["gRecord Ahead", "Left(gRecord Ahead, Position(gRecord Ahead, "¶", 1, PatternCount(gRecord Ahead, "¶")) - 1)"]
    If ["gGo which File = "Away""]
      ** Set Field []
      ** Perform Script [Sub-scripts, <unknown>]
    End If
    ** Go to Related Record []
    Go to Layout ["gGo which Layout"]
End If

The Ahead button does essentially the same thing as the Back button, only in reverse. It removes information from the g_Ahead fields, places it in the g_Back and gGo which fields, then takes you there.

Layouts
Go into Layout mode and move the fields around, resizing them until they look like figure 1. Under the "Go" header from left to right, the fields are in this order: gGo which File, gGo which Layout, gGo which Record. Under the "Back" header, the fields are in this order: gFile Back, gLayout Back, and gRecord Back. Finally, under "Ahead," the fields are gFile Ahead, gLayout Ahead, and gRecord Ahead. Using the Button tool, create some buttons, attach the appropriate scripts and add text to them to match figure 1. The white area between the "Previous" and the "Next" buttons is the "Record ID" field. You can delete the "Connect" field from the layout. For those of you who will be adding this to an existing solution, you won't even need any of the fields on the layout. However, if you do want to place them on the layout just to see how it works, you'll have to use the field tool and drag the new fields onto the layout. Now, select Mode > Duplicate Layout, and change the Layout 1 title to Layout 2 (and vice versa) on the Layout 2 button. Double-click on what is now called the Layout 1 button and assign the "Go to Layout 1" script to it. In ScriptMaker, redefine the "Go to Layout 2" script so it goes to Layout 2. In Browse mode, create three or four more records by selecting Mode > New Record.

Figure 1: Field and button layout - Try to make your screen look something like this, so the instructions in the body of the article will make sense.

The second file

Now, select File > Save a Copy As. Then, make a copy of the file you've been working in and name it Away, using the "Type - copy of current file" option. Go ahead and open the new Away file. Select File > Define > Relationships. Create a relationship back to the Home file using the Connect field:

Relationship Name

Relationship

Related File

Home

Connect = ::Connect

Home

Most of the fields won't be needed in this file. Because FileMaker Pro is a relational database, you can access the fields in the Home file that store your maneuvers. To display the fields from the Home file, go into Layout mode. Double-click on the upper-most field, gGo which File. When the Specify Field window appears, click on the upper box with the words Current file ("Away") in it. Drag it down to Home and let go. Click on ::gGo which File to select it and click on OK. Do the same to convert the other fields to their related counterparts, but leave the Record ID field as it is because it refers to records in this file.

While you're at it, do the following:
1. Change the text to indicate this is File 2 instead of File 1.
2. Change the text on the Go to File 2 button so it reads: Go to File 1.
3. Copy these fields in a group.
4. Switch to the second layout.
5. Delete the corresponding fields in Layout 2.
6. Paste the fields from the clipboard into the same position.
7. Change the header to File 2, and change the background color if you decide to do that.

I also used a different background color on both layouts in the second file. This way, when I'm clicking through the files, I have another visual cue that I've arrived somewhere else. Of course, there's no need to do that if you're working with an existing solution.

Four of the scripts in the Away file are now going to need some surgery so they all refer back to the Home file. In ScriptMaker, edit the Remember Where You've Been script. Everywhere you see the small letter "g" as part of a field name, replace it with Home::g. For instance, If ["not IsEmpty(gFile Ahead)"] becomes If ["not IsEmpty(Home::gFile Ahead)"]. All the Set Field steps need changes when you Specify Field... and Specify... the calculation. Of course, you'll have to choose which field you set by hand. When you're done with the Remember script, do the same to the Back Button and Ahead Button scripts. Change the Land Here script so it reads as follows. Use the Specify: Layout number from field... for the first step. For the second step, use the Specify: By Field Value...:

Script name: Land Here (File: Away)

Go to Layout ["Home::gGo which Layout"]
Go to Record/Request/Page ["Home::gGo which Record]
Halt Script

Click on "Go to File 2" script and rename it "Go to File 1". Click on the "Edit..." script button. The second step reads:

Perform Script [Sub-scripts, <unknown>]

Click on the Specify... button and come down the External Script... Choose the "Home" file and come down to the "Land Here" script. Click on OK, click on OK again, and click on the Done button to exit the ScriptMaker.

Under the File menu, choose Define Fields. Rename gFile Back to gRecord. Now you can delete all the other Global fields. When you're done, you should only have three fields left: Connect, Record ID, and gRecord.

Go back into Define Relationships by selecting File > Define > Relationships. In the dialog that appears, click on New. When the File dialog appears, select the Away file and create the following:

Relationship Name

Relationship

Related File

Which Record

gRecord = ::Record ID

Away

Usually, relationships are created between two different files. However, this relationship effectivelly connects the file to itself. This so-called "self-join" relationship lets you paste a record number into the Global "gRecord" field and immediately go to that record in the Away file using the "Go to Related record" script step. As long as the record is in the current found set, Go to Related Record has the added advantage of leaving any found set alone. Otherwise, it performs a sort of "Find All." This only happens if you don't select the "Show only related records" check box. Before you leave the Away file, go back into ScriptMaker. In the Back and Ahead buttons scripts, the last seven steps are different than those in the Home file. They can now be filled out because the relationships to the Home file are complete.

Script Name: Back Button (File: Away) (last seven steps)

   If ["Home::gGo which File = "Home""]
      Perform Script [Sub-scripts, "External: "Home" [Land Here]"]
   End If
   Set Field ["gRecord", "Home::gGo which Record"]
   Go to Layout ["Home::gGo which Layout"]
   Go to Related Record ["Back Record"]
End If

Note that if the second step above, the words "Land Here" refer to the name of the script in the Away file. I'll use that convention in the scripts that follow:

Script Name: Ahead Button (File: Away) (last seven steps)

   If ["Home::gGo which File = "Home""]
      Perform Script [Sub-scripts, "External: "Home" [Land Here]"]
   End If
   Set Field ["gRecord", "Home::gGo which Record"]
   Go to Layout ["Home::gGo which Layout"]
   Go to Related Record ["Which Record"]
End If

Home again, home again
Go back to the Home file. Select File > Define > Relationships. Create the following:

Relationship Name

Relationship

Related File

Which Record

gRecord = ::Record ID

Home

Away

Connect = ::Connect

Away

Now, go back into ScriptMaker and complete the final steps in the Back Button, Ahead Button, and Land Here scripts:

Script Name: Back Button (File: Home) (last seven steps)
    If ["gGo which File = "Away""]
      Set Field ["Away::gRecord", "gGo which Record"]
        Perform Script [Sub-scripts, "External: "Away" [Land Here]"]
    End If
    Go to Layout ["gGo which Layout"]
    Go to Related Record ["Which Record"]
End If

Script Name: Ahead Button (File: Home) (last seven steps)
    If ["gGo which File = "Away""]
       Set Field ["Away::gRecord", "gGo which Record"]
        Perform Script [Sub-scripts, "External: "Away" [Land Here]"]
    End If
    Go to Related Record ["Which Record"]
    Go to Layout ["gGo which Layout"]
End If

Script Name: Land Here (File: Home)
Go to Layout ["gGo which Layout"]
Go to Record/Request/Page ["gGo which Record"]
Halt Script

Finally, click on the "Go to File 2" script and click on the "Edit..." script button. The second step reads: Perform Script [Sub-scripts, <unknown>]. Click on the "Specify..." button and come down the "External Script..." Choose the "Away" file and come down to the "Land Here" script. Click on OK, click on OK again, then click on Done to exit ScriptMaker.

Try it out
Whew! At last, you're ready to see what this solution can do. Start clicking the buttons in any order you can dream up. Watch the info in the Global fields change. Try the Back and Ahead buttons. When you get all the way back, nothing happens. You can add a step that beeps if the gFile Back field is empty. Same with the Ahead button. You might make the buttons dim if they're unusable. You might even add a Home and End button to take you to either end of the Back and Ahead chain. You'll certainly need a "New Record" button. All these options and a few others are available at http://www.advisor.com.

You can use this with any number of files. Notice the If statement near the end of the Back and Ahead buttons scripts, If ["gGo which File = "Away""]. You'll need an If for each additional file you'll be using. You'll have to duplicate that script with the "Home::gGo which File" in all the external files as well. One of the advantages of this system is that you don't need any of the fields to appear anywhere on any layouts. All this can happen invisibly. Because of the complex scripting, you may want to build the method into some of your regular templates so you don't have to start from scratch each time you start a project. There are some limitations in the system. First, this plan can't undo anything. If a record is deleted, it's gone! Second, it cycles through the same layouts, records, and files as many times as you go to them. If you want to keep going back and forth between the same layouts a hundred times, that's what will happen. This plan doesn't store just a single location reference.

Another restriction is that you have to attach the Remember Where You've Been script to all navigation buttons in all Layouts. You'll probably want to keep people away from the Window menu and the Layouts pop-up menu. Any other forms of navigation they use will not be recorded for playback. The more knowledge your client has about backdoor navigation, the less valuable the system. You might want to add the Toggle Status Area [Hide, lock] script step to the Clear button in each of the files, to prevent users from accessing the Layouts pop-up.

A warning to those of you who want to include Find pages in this process. Depending on how you set up your finds, your user could end up on a page where they're used to entering data into empty fields while in Find mode. You don't want someone going there and overwriting the data in live records! The same warning applies to landing in layouts that normally display reports in Preview mode. Without the proper Sort and Preview Mode commands, those pages could look completely foreign. The idea is to make things easier for your clients. To prevent accidentally accessing those pages, don't add the sub-script Remember Where You've Been to any of the buttons that go to those pages.

Summing up
Using techniques from the files I've just shown you, you'll be able to add browser-like Back and Ahead buttons to your solutions. This capability adds power to an already great set of files. Now, the question is: Can you get your users to pay for it?

 

© 1998 Jonathan Stars

< Back to In the News

 

 
   
Email us here.