Branching and Looping in Scripts
Now that you have a basic foundation in what scripts do and how you can run them, it's time to see some of ScriptMaker's more powerful features. The script you created at the beginning of this chapter was the simplest kind: It goes through a series of steps from start to finish every time. Sometimes your script needs more smarts. You can add steps to the script that cause it to take different actions depending on the situation (called branching) or make it do the same thing over and over again (called looping).
POWER USERS' CLINIC Context Independence |
You may be wondering why the Send Email to Customer script you created on these pages doesn't go to the Customers layout first. After all, doesn't it only make sense from this context? Actually, this script is a perfect candidate for context independence (Section 13.2). What happens if you run this script from the Jobs layout? It creates a new email message addressed to the related customer. That message sounds pretty useful. The same holds true from the Invoice layout. In fact, you can run this script from any layout and get a useful result: FileMaker finds the related Customer record and addresses the message to her. But what if you have multiple related customer records? (Remember, the Send Email to Customer script is set to send only one email, even though the Send Mail script step lets you send multiple emails to all customers in a found set.) If you just run the script from the Scripts menu, FileMaker automatically selects the first related customer based on the active record on the current layout. (If the relationship to Customers is sorted in the Relationships tab of Define Databases, it'll be the customer that sorts to the top. Otherwise you get the oldest customer record.) But if your layout has a portal of related customers, you can put a button inside the portal row. Then, when you click this button, the script automatically addresses the email to the appropriate related customer, even if he's not the Customer in the first related record. The point is you can put a button just about anywhere and tell it to run this script. FileMaker does something a little different depending on where the button is. So this example is one of those scripts that you don't want to associate with a specific layout. |
13.4.1. Branching with If, Else If, Else, and End If
If you're comfortable with the If and Case functions in calculations (Section 11.2.1.2), then you'll feel right at home with this topic. You've noticed that you often look someone up in the Customers layout, copy his email address, and then go to your mail program to send him an email. You'd like to add a button to the Customers layout that creates the email directly, saving you all the trouble of copying, switching, and pasting.
You can use FileMaker's Send Mail script step, which is just like the File
- Choose Scripts
ScriptMaker. Then, in the Define Scripts dialog box, click New. In the Script Name box, type Send Email to Customer.
When you want to run this script, you choose this name from the Scripts menu.
- In the list of available script steps, select Send Mail, and then click Move.
FileMaker adds the script step to the script.
Note: The Send Mail script step is under Miscellaneous near the bottom of the list. If you don't like looking through this long list, choose Miscellaneous from the View pop-up menu to see just the steps in this category. Whenever you're not sure which category holds the step you want, choose "all by name" from the menu to see every step in alphabetical order.
- In the Script Step Options area, turn on the "Perform without dialog" checkbox.
This tells FileMaker you don't want a window that lets you enter or edit the Send Mail Options dialog box when the script runs. In this case, you just want it to do its work as you specify in the script step.
- Click Specify. Then, when the Send Mail Options dialog box appears, click the pop-up menu to the right of the To field. Choose Specify Field Name.
You now see a Specify Field dialog box. Here, you tell FileMaker where to find your customer's email address. Make sure "One email using data from the current record" is selected or you could get some dicey results, like sending an email about a Customer's recent Invoice to all the Customers who happen to have records in your found set.
- Switch to the Customers table, if necessary, and then choose the Email address field. Click OK.
FileMaker closes the Specify Field window and shows you the Send Mail Options window again. Now, though, it shows your Email Address field reference in the To field. You can also add field references or calculations for CC, BCC, Subject or even the body of your email message in those fields. This dialog box even lets you choose a file to attach to your email. But for now, just leave all these options blank.
Tip: Turn on the "Multiple emails (one for each record in found set)" option to use this script step to send email to more than one person at the time. But remember, use this option for good, never for evil. You'd never send spam emails, would you?
- Click OK again.
You now see your single line script in the Edit Script dialog box again, with the Send Mail options [No dialog; To Customers::Email Address] listed as reference.
At this point you have a working script. If you run it, it indeed creates a new email addressed to the current customer. But what happens if you don't have an email address for this customer? If the Customers::Email Address field is empty, your script tries to send an email without a valid address to your email program, which complains mightily. Fortunately, you can head this problem off at the pass. If the Email Address field is empty, you'd rather have your script tell you about it and skip the Send Mail step entirely. This is a job for the If step, so add it as follows:
- In the Edit Script dialog box (Section 13.1.3), add the If step to your script.
FileMaker adds this step after the Send Mail step. It also adds a third step: End If. You can't have an If without an End If, so you get both automatically.
Note: If you accidentally delete the End If step from your script, FileMaker shows an error message when you try to save the script. To fix the error, you need to add the End If step back to your script and drag it to its proper place.
- Using the little arrows to the left of the If step, drag the step up above the Send Mail step.
The process of moving a script step in a list is a familiar operation. It works just like moving fields, layouts, and so forth. By rearranging the steps in your script, you're telling FileMaker what order they should run in. (A script won't work if you've got a step above something that needs to happen first.)
Also, notice that the Send Mail script step is now indented. Everything between If and End If indents automatically to remind you that you're inside an If condition.
- Select the If step and, in the Script Step Options area, click Specify.
FileMaker shows you a standard Specify Calculation dialog box like the one shown on Section 9.2. You use a calculation to define the condition of this If step. If the calculation evaluates to True, FileMaker does the steps after the If. If the calculation evaluates to False, FileMaker skips to the End If and continues running the script from there.
- In the calculation box, type Not IsEmpty(Customers::Email Address), and then click OK.
This calculation evaluates to True and sends your customer an email only if the Email Address field isn't empty. See the box on Section 13.4.1 for details on how this calculation makes these decisions.
Your script now checks to see if the Email Address field has something in it before running off to create the email message. But what happens when you run the script and the Email Address field is empty? Right now, nothing at all. FileMaker evaluates the If condition, sees that it's false, and skips to the End If. There's nothing after the End If, so the script just stops and your user waits in suspense, until he finally realizes that the requested email message simply isn't coming and investigates the problem on his own…or chucks his computer out the window.
UP TO SPEED Not What? |
FileMaker lets you create calculations that involve layers of Boolean logic. In the script you wrote on Section 13.4.1, the If script step runs the indented steps only when the whole calculation evaluates to True. To figure out when that happens, you have to deconstruct the calculation itself. By itself, the IsEmpty function returns True when the value you pass to it is completely emptyin other words, when the Email Address field is empty: IsEmpty (Customers::Email Address ) But that doesn't help you because you only want the email sent when there is data in the email field. If you have no email address entered, the calculation above returns True, and causes the Send Email step to run. If the email address field is filled in, on the other hand, the calculation's result is False and FileMaker skips the Send Mail step. This behavior is exactly the opposite of what you want. To flip the result of the calculation around, you use the Not operator. It looks at the Boolean value to its right, and turns a true to a false, or a false to a true. Here's the calculation you need: Not IsEmpty ( Customers::Email Address ) You can easily tell if you've got the right construction by reading the If step like a sentence: "If not is empty Email Address." It may not be grammatical perfection, but it does get the logic right. |
In the interest of preventing property damage, it's better for your script to tell the user why nothing's happening. For example, you can have your script open a message box when the If condition is false, saying, "You can't email this customer, since there's no email address on file," or whatever. You can get exactly what you want with the Else step:
- Return to your script in the Edit Script dialog box (Section 13.1.3). Select the Send Mail script step in your script.
When you add a new step, FileMaker inserts it after the selected step. You want the Else step to go right after the Send Mail step, so you select that step first.
- Add the Else step to the script.
FileMaker inserts an Else step between Send Mail and End If.
Note: Don't click the Else If step by mistake. You want the step called just Else. If you added the wrong step, select it, click Clear, and try, try again.
- Right after the Else step, add the Show Custom Dialog script step to the script.
This step is also under Miscellaneous. Its job is to pop up a dialog box for the user. You get to decide what the box says, which buttons it includes, and which fieldsif anyit should show.
- Click the Specify button in the Script Step Options area.
The Show Custom Dialog Options window (Figure 13-11) appears.
Figure 13-11. When you choose options for the Show Custom Dialog script step (step 3 on Section 13.4.1), you get a window like this. For example, you can give your dialog box a title, message, and up to three buttons. You can also add input fields to the dialog box by visiting the Input Fields tab. You'll learn about these on Section 15.2.3.
- In the Title box, type No Email Address.
This controls what shows in the title bar along the top of your custom dialog box.
- In the Message box, type You can't email this customer, since there's no email address on file.
This tells FileMaker what to put inside the dialog box.
- From the Button 2 box, select and delete the word Cancel.
A custom dialog box can have up to three buttons. In this case, you want only one: an OK button. To keep the other buttons from showing up, just make sure there's nothing in the Button 2 and Button 3 boxes.
- Click OK.
Your script should now look like the one shown in Figure 13-12.
Just click OK twice to return to your database, and try your script out: Select a customer without an email address (enter Find mode, type ">0" in the Email address field, then click the Omit button), and choose Scripts
|
POWER USERS' CLINIC Testing Multiple Conditions |
If you have more than one condition to consider, you can use the Else If script step. It works a lot like the Case function in a calculation. You could have a script like this, for instance: If [ Get ( CurrentTime ) < Time ( 12 ; 0; 0 ) ] Show Custom Dialog [ "Good Morning!" ] Else If [ Get ( CurrentTime ) < Time ( 18 ; 0 ; 0 ) ] Show Custom Dialog [ "Good Afternoon!" ] Else Show Custom Dialog [ "Good Evening!" ] End If When this script runs, it tests each condition in turn, deciding which custom dialog box to show your user, based on the actual current time. If the current time's before noon, your user sees a "Good morning" message and the script jumps to the end (the End If script step) without needing to test the second condition. If it isn't before noon, the script does a second test to see if it's before 6 p.m. If it is, the user sees a "Good Afternoon" message and the script jumps to the end. But if both tests fail, no third condition is tested, and the Else just shows the "Good Evening" message, like a default condition in a Case statement. However, you can add other Else Ifs to test other conditions. You can add as many Else If steps as you want, but they must come between the If and Else If steps. Each Else If can test a different condition. If you have an Else step, it should come after the If and every Else If, but before the End If. For a really cool way to tell which of the conditions in your scripts are evaluating as True and which ones evaluate as False, see the section on Script Debugger on Section 19.1.1. |
13.4.2. Looping
Sometime you want to do the same thing over and over again, until you reach some kind of end point. For example, people often write a script that does something to every record in the found set, one after another. This kind of scripting is called looping. You make a script loop through records using the Loop script step.
Like the If step, the Loop step has a necessary partner called End Loop. When you put script steps between Loop and End Loop, FileMaker simply repeats them over and over, forever.
POWER USERS' CLINIC Go to Record/Request/Page |
Since looping through the records in the found set is such a common operation, FileMaker lets you do it with a simplified set of script steps. For example, if you want to delete the Email Address field in every record in the found set (say you no longer want to email local customers, just out-of-state ones), you might think you'd have to approach the problem like this: Loop Set Field [ Email Address, "" ] Go to Record/Request/Page [ Next ] Exit Loop If [ Get ( FoundCount ) = Get (RecordNumber) ] End Loop Set Field [ Email Address, "" ] This script first starts a loop. It then clears the Email Address field in the current record. Next, it moves to the next record (just like clicking the right-hand page in the Book icon). If the number of the record you're now on equals the current found count, FileMaker exits the loop. But when this loop exits, you still haven't cleared the last email address. The Exit Loop If step exits when you first reach the last record. You have to add the last step (a copy of the Set Field step in the loop) to clear the Email Address in this last record. But the Go to Record/Request/Page script step has some special powers. When you choose the Next option (telling it to go to the next record), a new checkbox appears in the Script Step Options area (shown here). This checkbox, called "Exit after last," tells FileMaker you want it to automatically exit the loop after the last record. (In other words, it happens when the Go To Record/Request/Page step is run and you're already on the last record.) This kind of scripting is good for two reasons. First, you can save the Exit Loop If step in your script, since FileMaker exits the loop for you. Second, since the exit happens after the last record, there's no need to add the last Set Field script step. The revised script looks like this: Loop Set Field [ Email Address, "" ] Go To Record/Request/Page [ Next, Exit after last ] End Loop In the real world, you probably wouldn't clear an email address just to keep an email from being sent. You'd make a field with a checkbox, then mark the records that need to get an email. When you write your looping scripts, you'll probably have more steps than the single Set Field shown here, and your scripts will grow accordingly. |
So how does a script like this end? Simple: You tell FileMaker to exit the loop at the right time. To this end, FileMaker has a script step called Exit Loop If. Like the If step, Exit Loop If has an associated calculation. If the calculation evaluates to True, FileMaker immediately skips ahead to the End Loop step, and continues with the step that follows. As such, a loop usually looks like this:
Loop # Do some stuff Exit Loop If [ // some condition ] End Loop
Using what you've learned in this chapter and about calculations in Part 4, you can easily build a script like this. For "some condition," just use a calculation that describes the condition when the loop should stop repeating itself. In the box on Section 13.4.2 you can see an example of a looping script that stops when every record in a found set has been used up.