Creating and editing scripts in FileMaker is fairly straightforward. Simply choose Scripts, ScriptMaker and the Define Scripts dialog opens. You can also use the keyboard shortcut (one of our favorite features added in FileMaker 7) of (-S) [Ctrl+S]. Keep in mind you'll need to have signed in with an account that allows script access.
After you're in ScriptMaker, you'll see a list of existing scripts and can manage all the scripts in your file (you can delete, reorder, and so on). From there you can delve into a single script and edit its individual script steps.
Writing an actual script requires first that you have a goal in mindwhat purpose is the script intended to accomplish? A script will step through a series of instructions, one at a time, until the script either reaches its last instruction or reaches some exit condition. Exit conditions can vary, and many of their implementations are covered in this chapter.
Here's an example of the logical outline of a script you might use to take users to a Main Menu layout after they log in. Presumably this script would be set to run when a file is first opened by an individual user. Assume that someone named Kim has just logged in.
After valid login, carry out these steps:
This simple four-step process takes care of some background tasks first, and then from a user's standpoint navigates to the main menu on which, presumably, a welcome message sits. All the user would see is that the system landed him on the Main Menu layout.
To implement a script like this, a developer would open ScriptMaker, create a new script, give it a name, and then use the Edit Script dialog to insert various steps into the script. The actual script that would manage the preceding logic could look like this:
Go to Layout [ "zdev_GlobalAdmin" (Globals) ] Set Field [ Globals::gAccountName; Get (AccountName) ] Set Field [ Current_User::LastLoginDate; Get (CurrentDate) ] Set Field [ Globals::gUserNameDisplay; Current_User::Name_First ] Set Field [ Globals::gUserMessage; "Welcome Back, " & Globals::gUserNameDisplay & "." ] Go to Layout [ "Main Menu" (Globals) ]
There are a number of ideas contained in the preceding example that we'll detail in the forthcoming pages. The important thing in this case is to become more familiar with reading a script and following its logic.
This script first goes to a layout called zdev_GlobalAdmin. It then posts information into four fields. One of these steps draws data from a related field in a Current_User table occurrence, and another sets information in that related record. The script then last navigates again to a Main Menu layout. This conforms to the flow we mapped out previously; you might think of the original four pseudocode steps as an outline for the finished script.
The ScriptMaker Interface
The Define Scripts dialog (see Figure 9.1) allows you to manage all the scripts in your current file. To reorder scripts, simply drag individual scripts up or down along the list. Unfortunately, there's no means of sorting scripts, so you need to do your best to stay organized. We generally advocate keeping scripts either grouped by function (for example, all your Invoicing scripts in a group) or organized alphabetically.
Figure 9.1. The Define Scripts dialog box allows you to create, edit, and organize your scripts, and decide which ones to display in FileMaker's Script menu.
Use (-up/down arrow) [Ctrl+up/down arrow] to move scripts via your keyboard.
You can perform various actions in the Define Scripts dialog box as outlined in the following list:
If you use FileMaker Pro 8 Advanced, one of the easiest ways to confirm that a script has imported or copied well is to run it the first time with the Script Debugger turned on.
For an example of the script template that the authors use in their consulting practice, see Chapter 27, "Documenting your FileMaker Solutions," p. 841.
Note also that just as in other areas of FileMaker, a single hyphen becomes a menu divider. If you create a script named -, you insert a divider in your list. This is useful in organizing your scripts visually. Plan to have a good many scripts; it is a good idea to keep them well organized.
Notice that by using (-click) [Ctrl+click] you can select multiple, noncontiguous scripts and then delete, duplicate, or print as you need. Shift-click selects multiple contiguous scripts.
Script Naming Practices
Keeping your scripts well organized and following good script naming practices is even more important in FileMaker 7 and 8. Versions of FileMaker Pro prior to 7 generally involved more individual files than today, and hence scripts tended to be naturally distributed throughout a given system. In a system in which one file can contain many tables, all your scripts may very well live in a single file.
FileMaker 8's capability to store many tables in one file has many implications, but in particular with scripts, you won't be constantly closing and reopening ScriptMaker in different files as you would have with FileMaker 6 or earlier. Fewer scripts are also required in many cases: Many operations that would have required executing a series of external subscripts across several files can now be accomplished by a single script in FileMaker 8.
Script naming practices vary quite widely from developer to developer; even the authors of this book find it difficult to agree to a common standard. It's less important that you follow any particular naming convention than that you use a logical and consistent system. We do, nonetheless, recommend you consider some of the following ideas:
To learn about how to implement custom menus in a solution, see Chapter 13, "Advanced Interface Techniques," p. 353.
After you create a new script in ScriptMaker, or edit an existing script, the Edit Script dialog opens (see Figure 9.2). Here you construct the actual script by inserting script commands from the list on the left into the window on the right. Nearly every script step has additional options you need to specify, such as the name of a layout to go to, or the name of a file from which to import. These options appear under your script when you highlight a given step in it.
Figure 9.2. The Edit Script dialog presents you with additional dialogs as needed to configure settings for specific steps in your script.
You can (-click) [Ctrl+click] multiple script steps at once and insert the batch into a script in one move.
To reorder script steps, simply drag them by the two-headed arrow icon located to the left of the step.
In FileMaker Pro 8 Advanced you can copy and paste script steps (and the same Shift-click and Ctrl-click behaviors apply as elsewhere). This works perfectly well from script to script and from file to file. This is also an alternative way to reorder script steps in a large script.
If Indicate Web Compatibility is enabled, script steps that are incompatible with web publishing display in gray.
As an example, Go to Layout is a common step you'll use quite often. Notice that when you insert it into a script, a menu appears in the Script Step Options area at the lower right, from which you can choose an existing layout, the layout on which the script began, or one determined by calculation.
Full Access Privileges
Notice the Run Script with Full Access Privileges check box at the bottom of the Edit Script dialog. Designating that a script run with full access privileges means simply that for the duration of that script, FileMaker will override all security restrictions. When this option is not enabled, scripts run subordinate to whatever privilege set the currently signed-in user has. For instance, if a script makes a call to delete a record and the user who is running that script cannot do so based on his current security privileges, the script usually presents an alert message to the user and ignores that step of the script. The rest of the script is still performed.
Note that when this option is checked, the security privilege set for the current user actually does change for the duration of the script: If you use the calculation function Get ( PrivilegeSetName ), it will return [Full Access] as long as the script is running. If your script contains logic in which you need to check a user's assigned privilege set, you'll need to capture the user's privilege set information elsewhere before running the script and refer to it however you've stored or captured the information.
Error management in scripts is an important element in all scripting. For more detail, see "Set Error Capture," p. 257.
To understand FileMaker security and privilege sets, see Chapter 12, "Implementing Security," p. 325.
Keeping track of what scripts do is a difficult task. What seemed perfectly intuitive at the time you wrote a given script may become hopelessly obscure a few weeksor sometimes even hourslater. Although developers vary in how they use comments, nearly all developers recognize the value of commenting their work.
Remember that you're not coding in a vacuum. We can virtually guarantee that although you may never intend that a given database be seen by someone else's eyes, if it stands the tests of time and proves useful, at some point you'll crack it open with the infamous words, "Let me show you how I did this...." Likewise, professional-grade systems are nearly all collaborative efforts. Comments exist to help your peers understand what your caffeine-sodden brain was thinking at the time you wrote a particular routine.
A simple example of a commented script is seen in Listing 9.1. Notice that in FileMaker Pro comments are prefixed by the # symbol.
Listing 9.1. Script with Comments
[View full width]
# Purpose: initiate the running of a report while allowing users # to choose what sort order they want # History: sl 2004 02 04; bb 2004 02 05 # Dependencies: Invoices: Monthly Report layout # # prompt user for sort order Show Custom Dialog [ Title: "Sort Order"; Message: "Do you want to sort by amount or date?"; Buttons: "Date", "Amount", "Cancel" ] # # check for cancel first If [ Get (LastMessageChoice) = 3 ] Go to Layout [ original layout ] Halt Script # # sort by Amount Else If [ Get (LastMessageChoice) = 2 ] Go to Layout [ "Monthly Report" ] Perform Script [ "Sort by Amount" ] # # sort by Date Else If [ Get (LastMessageChoice) = 1 ] Go to Layout [ "Monthly Report" ] Perform Script [ "Sort by Date" ] # End If
Using a Script Template
It is often helpful to create a template script that you can duplicate when you need to create a new script. In our templates, we include several comment lines at the top where we record information about the purpose and revision history of the script. A template script looks something like this:
# purpose: TYPEHERE # dependencies: TYPEHERE # history: XXX DATE # # set error handling Allow User Abort [ Off ] Set Error Capture [ On ] # # establish context Go to Layout [ Original Layout ] # #
Although it is simple, this template does save time and promote good code. If you don't need a particular piece of it, it's easy enough to delete.
Adding the Go to Layout step to your template can help ensure that the script begins on the correct layout and thus is associated with the proper base table attached to that layout. Including this step in the template prompts developers to make a conscious decision and reminds you that context needs to be managed.
One of the most useful things in ScriptMaker is the Perform Script step itself. One FileMaker script can call another script, which is then commonly known as a subscript. This then allows you to divide scripts into smaller logical blocks and also break out discrete scripts for anything you are likely to want to use again. This degree of abstraction in your system is one that we very much recommend. Abstraction makes scripts easier to read, easier to debug, and modularin that a subscript may be generic and used in a variety of scripts.
Here's an example:
[View full width]
Sales_Report # purpose: to run the Sales Report, weekly or monthly # history: scl 2-5-2004 # Perform Script [ "CheckPermission_forSales" ] Perform Script [ "Find_CurrentSales" ] # Show Custom Dialog [ Title: "Run Report"; Message: "Would you like this report broken out by Weekly or Monthly subtotals?"; Buttons: "Monthly", "Weekly", "Cancel" ] # If [ Get (LastMessageChoice) = 1 ] Perform Script [ "Monthly_Report" ] # Else If [ Get (LastMessageChoice) = 2 ] Perform Script [ "Weekly_Report" ] # End If
Notice that the script actually doesn't do much on its own. It will first run a permission check script, and then run another script to establish a found set. It then prompts the user to make a choice and runs one of two report subscripts based on what choice the user makes. This approach is quite common and demonstrates a flexible approach to programming. The Find_CurrentSales subscript could well be used elsewhere in the database. Creating separate routines for weekly and monthly reports makes the script more readable; imagine seeing all the logic for those two reports embedded here as well.
As another example of script abstraction, imagine sorting a contacts database by last_name then first_name for a given report. If you've written a script to produce that report, sorting is a step in the process; however, odds are that you'll want to be able to sort by last_name, first_name againperhaps for a different report, perhaps as a function that lives on a list view or in a menu, or perhaps before running an export script (or perhaps all the above). Whenever reasonable, we recommend looking for ways to abstract your code and foster reuse. It saves time and complexity if suddenly your client (or boss) comes to you and says you need to now present everything by first name. If that logic lives in one place, it's a one-minute change. If you have to hunt for it, the change could take days and require extensive debugging.
Even if you're not planning to reuse blocks of code, it's still a good idea to break scripts into subscripts. They're easier to read, they're easier to enable and disable during testing, and they allow you to name them in logical ways that are comprehensible even at the Define Scripts dialog level.
Some other good candidates for subscripts are sort and find routines; these are often reusable by a wide range of scripts or by users as standalone functions. Other uses of subscripts might be for the contents of a loop or If function. Sometimes it's easier to separate logic into separate paths by dividing logical groups into separate scripts, as in the example we gave a little earlier. When you have a branching script (covered later in the chapter), it's helpful to encapsulate a single branch in a subscript. This allows you to see the flow of logic in the parent script and cover each branch in its own respective subscript.
Common Scripting Topics
Part I: Getting Started with FileMaker 8
Using FileMaker Pro
Defining and Working with Fields
Working with Layouts
Part II: Developing Solutions with FileMaker
Relational Database Design
Working with Multiple Tables
Working with Relationships
Getting Started with Calculations
Getting Started with Scripting
Getting Started with Reporting
Part III: Developer Techniques
Developing for Multiuser Deployment
Advanced Interface Techniques
Advanced Calculation Techniques
Advanced Scripting Techniques
Advanced Portal Techniques
Debugging and Troubleshooting
Converting Systems from Previous Versions of FileMaker Pro
Part IV: Data Integration and Publishing
Importing Data into FileMaker Pro
Exporting Data from FileMaker
Instant Web Publishing
FileMaker and Web Services
Custom Web Publishing
Part V: Deploying a FileMaker Solution
Deploying and Extending FileMaker
FileMaker Server and Server Advanced
Documenting Your FileMaker Solutions