Common Scripting Techniques

 <  Day Day Up  >  

We will now delve into some useful and common scripting techniques. This is not meant to be a comprehensive list ”the Beep script step should be fairly obvious to you ”but rather these are the important areas to understand. They will help you establish a solid foundation in scripting.

For a reference to all the script steps in FileMaker 7, see Appendix C, p. 927 .


Error Management

Error management is an important part of the scripting process. Frequently scripts make assumptions about the presence of certain data, the existence of certain objects, or depend on layout to establish context. If any of a given script's assumptions are not met, it either might not work or might produce unintended results. Error management involves identifying these assumptions and creating ways of dealing with them. You can bank on users finding odd, unpredictable ways to break your system. Applying some thought to how to manage such situations will serve you well in the long run.

FileMaker Pro's error handling is somewhat limited, but you do have some tools at your disposal.

For further discussion of error handling, see "Handling Errors in Scripts," p. 486 .


graphics/troubleshooting_icon.jpg

To explore problems with error messages you think are being wrongly suppressed in scripts, refer to "Lost Error Messages in Script " in the Troubleshooting section at the end of this chapter.


Allow User Abort

Allow User Abort enables and disables a user's ability to hit the Esc key (or graphics/shift.gif -period on a Mac) to cancel a script in midstream. Generally speaking it's the rare script that's designed to be cancelled gracefully at any time in its process. There's really no reason to ever turn Allow User Abort on, unless you're testing a loop script or some other long-running process. Any script without Allow User Abort disabled allows users to cancel a script in progress, with consequences that you may not intend.

The other thing Allow User Abort does is take away the Cancel button when a script pauses, giving users only the option to continue. There are many cases where canceling a script would leave them stuck on a report layout or stranded midstream in some extended process.

graphics/troubleshooting_icon.jpg

To learn more about how to deal with incomplete script completion (atomicity in database lingo), refer to "Unfinished Scripts" in the Troubleshooting section at the end of this chapter.


Set Error Capture

The Set Error Capture script step either prevents or allows error messages to be displayed to the user. When turned on, the script in question captures errors before presenting them to the user.

Handling errors well in scripts is a black art: Its difficult to always anticipate what errors will crop up. For more information on using the Set Error Capture script step, see Chapter 17, "Troubleshooting," p. 475 .


It is possible, and very much preferable, to use the Get(LastError) calculation function to programmatically deal with errors within your script. The technique you'll need is to use the If function to test Get(LastError) and present dialogs to the user as appropriate. Refer to FileMaker Pro's online help system for a list of error codes.

Be careful with this script step. It certainly doesn't prevent errors from happening ”it simply and rightly doesn't show the user a message about one that did. An error may happen, but the user's experience won't be interrupted to deal with it. This allows you to control how errors are managed within your script itself. You should not turn error capture on unless you have also added steps to identify and handle any errors that may arise.

If you have set up your own custom error handling routines, you'll clearly prefer to turn FileMaker Pro's standard alerts off.

Setting and Controlling Data

One of the primary uses of scripts lies in manipulating, moving, and creating data. Most of the script steps for manipulating field data are found in the Fields category.

Essentially these Fields steps allow you to insert data into a given field programmatically, just as a user otherwise would. This can mean setting the field contents to the result of a calculation, copying the contents of one field into another, or simply inserting whatever is on the user's clipboard.

As an example, imagine that you wanted to give users a button that would insert their name , the current date, and the current time into a "comments" field, then place the cursor in the proper place for completing their comment:

 

 # purpose: To insert user and date/time data into a comment field, preserving the existing graphics/ccc.gif information, and place the cursor in the correct position for the user to begin typing. # dependencies: Need to be on the Main_Info layout, with the Comment field available. The graphics/ccc.gif script takes the user there. # history: sl 2004 jan 25 # # Allow User Abort [ Off ] Set Error Capture [ On ] # # Go to Layout [ "Main_Info" (Movie) ] # #    this next step applies the comment info in italics. Set Field [ Movie::Comment; TextStyleAdd (Movie::Comment & "" & Get (AccountName) & " " & Get (CurrentDate) & " " & Get (CurrentTime); Italic) & "" ] # Go to Field [ Movie::Comment ] Commit Records/Requests [ No dialog ] 

NOTE

This script includes the full commenting approach described in this chapter and the two Allow User Abort and Set Error Capture steps. From here on out, we'll forego those details in the interest of brevity.


When using a Go to Field step, FileMaker Pro places the cursor at the end of whatever content already exists in the field, unless the Select/Perform option is enabled, in which case the entire field will be selected.

Notice that the comment info is nested within a TextStyleAdd() function so that it will be displayed in italics.

For more information on calculation functions, including text formatting, see Chapter 8 "Getting Started with Calculations," p. 213 , and Chapter 14, "Specialized Calculation Functions," p. 381 .


Set Field is by far the most used of the field category steps. The other functions in this category nearly all depend on the field in question being on the layout from which the script is being performed. You should get into the habit of using the Set Field command whenever possible. It doesn't depend on a field being on a specific layout ”or any layout, for that matter ”and it usually can accomplish what you're trying to do with one of the other steps.

You'll generally need the insert script steps only when you expect user input. For example, you might place a button next to a field on a given layout called "index" that then calls up the index for a given field and waits until the user selects from its contents.

That script could often be a one-step script: Insert from Index (table::fieldname) . As always, you'd use your template for clarity, but this script would open the index for a given field and wait for the user to select a value. Again, you should tend to think of scripts as evolutionary. Consider writing a script even for one-step processes.

graphics/troubleshooting_icon.jpg

To manage cases where your script seems to be affecting the wrong portal row or related record, refer to "Editing the Correct Related Records" in the Troubleshooting section at the end of this chapter.


For more discussion on indexes, see "Storage and Indexing," p. 82 .


CAUTION

You may also discover the Copy , Cut , and Paste script steps. These work as you would expect. Copy and Cut place data onto the user's clipboard and Paste inserts from it. Cut and Copy overwrite anything already on the user's clipboard. Furthermore, Copy, Cut, and Paste depend on having access to the specified fields, and are therefore layout dependent. If, for some reason, you remove those fields from the specific layout in the future, your script will stop working. You should almost never use copy and paste for these reasons, and should defer instead to Set Field .


For further discussion of layout dependencies, as well as other types of dependencies that can get your scripts into trouble, see "Context Dependencies," p. 498 .


Another example of using the Set Field script step details how you might work with totaling child record data calculations. Often a simple calculation field with a Sum (related field) function works, but consider that with a large related data set, performance can become a problem. Furthermore, you cannot index that sort of a calculation field ”which might prove problematic for users performing Find requests or for your needs as a developer. Consider instead creating a script to calculate your totals and calling that script only on demand.

Providing User Navigation

You might have noticed in FileMaker's Edit Script dialog a subsection broken out for navigation. One of the most common uses of scripts is to provide a navigation scheme to users whereby they can navigate from layout to layout, record to record, or window to window by using buttons or some other intuitive means.

There's not too much magic here: By using the Go to Layout script step, you'll get the fundamentals. Consider placing buttons along the top of each layout that offer a means of navigating to all user- facing layouts in your solution with a Go to Layout script attached.

By building complete navigation scripts, you can control the entire user experience of your solutions and can opt to close the status area if you wish. Armed with find routines, sort buttons, reporting scripts, and a navigation interface, it is possible to build a complete application with a look and feel all its own.

Navigation can become quite complex. At the simplest level, a script attached to a Go to Layout command qualifies, but it's also possible to abstract a system by using the Go to Layout Name by Calculation options. It is now possible in this latest version of FileMaker to write one global navigation script for your system and control things by the attributes that you feed it.

For an explanation of advanced navigation techniques, see Chapter 13, "Advanced Layout Techniques," p. 353 .


Script Context and Internal Navigation

Consider that FileMaker uses layouts to determine script context: For any script step that depends on a specific table, you need to use Go to Layout steps to provide that context. If, for example, you need to create a related record in a child table, your script acts on context. Consider the following:

 

 New Line Item # assumes that the tempInvoiceID holds the key value the system needs to establish a graphics/ccc.gif relationship from LineItems to Invoices # Go to Layout [ "LineItems" (LineItems) ] New Record/Request Set Field [ LineItems::keyF_invoiceID; Globals::tempInvoiceID ] Commit Records/Requests [ No dialog ] Go to Layout [ original layout ] 

The script takes itself to the LineItem layout, executes some steps (in this case creating a record and then setting a key field) and then returns to the original layout.

NOTE

One technique is used in the script that helps make the script more portable: Notice that it doesn't assume anything about where it originated. You could call this script from anywhere in your system and, assuming your tempInvoiceID held either a proper value or intentionally did not, the script would perform just as you need.


The point here is that you'll need to bring a script to a specific layout to establish a different context. The user might never see this going on, but if you were to walk through the script step by step, you'd see the system go to the LineItem layout and then return to the layout from which the script originated.

Multi-file Navigation

Navigation becomes a bit more complex when you're working with multiple files. In general, placing all your user interface layouts in just one of your files is a good idea, but that doesn't save you from having to manage script context. To navigate to layouts external to your current file, you need to create "go here" scripts (that utilize a Go to Layout step) to be called as subscripts in your destination files. Also remember that if you want the user to visually see the new layout, you'll need a second step in your Go Here script: Select Window ("current") .

For a discussion of data-separation strategies, whereby you isolate your interface elements in one file, see "Separation of Data and Application Logic," p. 205 .


It is helpful to distinguish scripts that reference external navigation as a reminder that the user might end up in a different file. Use a suffix such as _ext to distinguish those scripts.

Saved Script Options

Scripts tend to mirror the actions a user could perform manually, but, obviously, do so without human intervention. It is possible in FileMaker to save Find, Sort, Export, and other actions in a script (hard-coding them, if you will), or to prompt the user for some input to help perform these steps.

The advantages of hard-coding requests should be fairly obvious. If, for example, you need to prepare a report on "active" real estate listings, it makes sense to have one of your script steps be a Perform Find that returns all the records with a status of "active." The requirements of your report will rarely change, so you'll save users time (and possible errors) if you hard-code the find request.

On the other hand, allowing the user to provide input is a great way to make scripts more flexible. Continuing the example, you might create a "real estate listings" report and then in your script prompt the user for some search criteria. This can be done by either using a dialog that gives them one or two choices (we'll cover that later in the chapter in the "Working with Custom Dialogs" section), or simply allowing the report to act on the current found set and sort.

You will often find it helpful to build pre-canned find and sort routines. For example, you might want a script for finding overdue invoices, or easy-access buttons for sorting by first name, last name, or company.

FileMaker allows you to save complex find, sort, export, and import requests as necessary, and allows you to edit these requests within ScriptMaker.

graphics/new_icon.jpg

FileMaker 7 has a wide range of dramatic scripting improvements: script parameters, window management, account management, but among some of the most noteworthy improvements is the ability to create explicit, editable find, sort, and export script steps. This alone is worth the price of admission.


Find Script Steps

FileMaker allows you to assemble and store complex find requests within scripts. In Figure 9.3, the script finds all overdue invoices over $500 and, in the same Perform Find step, omits invoice number 2004.1.1; the result replaces the found set.

Figure 9.3. Assemble as many find requests as necessary.
graphics/09fig03.gif

Notice that multiple requests have been added; this enables you to perform Or finds where you will be left with records that match either the first condition or the second.

A single Find request is assembled via the Edit Find Request dialog (see Figure 9.4).

Figure 9.4. By adding multiple criteria to a single find request, you will be performing an And search.

graphics/09fig04.gif


Note in Figure 9.3, however, that we have opted to omit records that match the second request. Setting a request to omit records simply means that FileMaker will find those records that match the overall request and then take out or ignore those that meet the omit criteria. If you create a find request that does nothing but omit records, it replaces your existing found set with all records that don't match your request. (How's that for a double negative?)

 

 Find_Overdue_Invoices Perform Find [ Specified Find Requests: Find Records; Criteria: Invoices::Total: "> 500" AND Invoices::DaysOverdue: "> 0" Omit Records; Criteria: Invoices::Invoice_Number: "= "2004.1.1"" ] [ Restore ] 

Other search-related script steps include Constrain Found Set and Extend Found Set . Just as though a user had chosen each command from FileMaker's menu-driven interface, Constrain reduces the current found set, eliminating any records that don't match the search criteria, and Extend adds those records from outside the set that match its criteria to the current found set.

Sort Script Step

Establishing saved sort orders in the Sort dialog works, happily, just as it does for users performing a manual sort (see Figure 9.5).

Figure 9.5. It's generally quite helpful to create sorting scripts for users. Sorting needs are usually fairly predictable and always needed more than once.
graphics/09fig05.jpg

One of the most common applications of sort scripts is in building column header buttons. Simply create a series of sort scripts and apply them to the buttons along the top of a list view (see Figure 9.6).

Figure 9.6. Scripting is often employed in creating more intuitive user interfaces for users.
graphics/09fig06.gif

Keep in mind that many of your reports depend on sorting, especially as you get into reporting by summary data. It's a good idea to create sort scripts for your reports and call them as subscripts, rather than hard-coding sort routines into your report scripts themselves .

You may well create reports that behave differently depending on different sort orders ”by setting up different, multiple subsummary parts on one report layout, for example ”so you'll want to factor the sorting logic into its own script or subscripts. A report with both a week-of-year sub-summary part and a month sub-summary part will display by week, by month, or by week and month depending on the sort options your script establishes. This is a handy technique for reducing the number of layouts you need in a system ”with a little bit of scripting you can use a single layout for three different reports.

For more on summary reporting, see Chapter 10, "Reporting with Grouped Data," p. 269 .


Using Conditional Logic

Another important element of scripting is the ability to branch scripts based on various conditions. To manage logically branching scripts, you use the If , Else , Else If , and End If script steps.

These conditional script steps work by performing a logical test, expressed as a calculation. If that calculation formula resolves to a true statement, FileMaker then executes all the script steps subordinate to (that is, nested within) an If or Else If statement.

Here's the idea, without troubling with FileMaker syntax:

 

 If person is a student    Go to school Else    Go to work End If 

In this simple logic, when you test to see whether a particular person is a student, he either will be or won't be. The test resolves to either a true condition or a false condition. This simple branch assumes that anyone who isn't a student should be going to work.

Let's add some complexity ”choose four possible avenues for, say, a family of four:

 

 If person is "Dad"     Go to work Else If person is "Mom"     Go to work after dropping kids off Else If person is a "kid"     Get dropped off at school Else If person is "Grandparent"     Start third career End If 

Okay, your family might not be quite so well organized, but this should give you the gist of things.

Logical conditions can be nested as well. Nesting allows you to define trunk-branch logic trees: What if it's Saturday?

 

 If today is a weekday     If person is "Dad"         Go to work     Else If person is "Mom"         Drop kids off at school         Go to work     Else If person is "kid"         Get dropped off at school         Learn     Else If person is "Grandparent"         Start third career     End If Else If today is a weekend     If person is "Dad"         Sleep in the hammock     Else If person is "Mom"         Visit friends     Else If person is "kid"         Spend the day with grandparents     Else If person is "Grandparent"         Watch the kids     End If End If 

These concepts should be fairly intuitive to follow. By using these sorts of nests and branches, it's possible to create some dramatically complex scripts. Don't forget that comments and breaking things into subscripts help with clarity.

Figure 9.7 shows an example of a real-world conditional script.

Figure 9.7. Notice that scripts within FileMaker's Script Editor are automatically indented. Liberal use of comments will help make scripts readable.
graphics/09fig07.jpg

graphics/troubleshooting_icon.jpg

To learn how to bake error checking into your conditional tests, refer to "Conditional Error Defaults," in the Troubleshooting section at the end of this chapter.


Using Loops

Another key scripting technique is looping. Looping allows you to execute a series of script steps over and over until some exit condition is met.

A simple example of this might be stepping through each record in an invoice table's found set and generating a new invoice for any that remain unpaid or that somehow need to be sent out again. The logic, again without worrying about syntax, looks like this:

 

 Go to first record in found set. Begin Loop.     Check whether the invoice is closed. (We'll assume unclosed invoices are those that graphics/ccc.gif need to be resent.)     If CLOSED         Go to next record.         If there is no next record (you're at the end of         your found set), then graphics/ccc.gif exit the loop (go to step 3).         Else begin loop again (go to step 2).     If NOT CLOSED         Close current invoice.         Create/duplicate new invoice. (In a real system, there would likely be more steps graphics/ccc.gif involved here.)         Go to next record.         If there is no next record (you're at the end of your found set), then exit the graphics/ccc.gif loop (go to step 3).         Else begin loop again (go to step 2). End Loop Exit Script 

Notice that an exit condition is established. The system tests, in steps, both If steps whether or not you're at the end of a found set.

Imagine you're a user doing this manually. You'd start at the top of a found set, use the book icon to page through each record one at a time, and then stop the process after you reach the end of your record set.

Here's another example, this time in FileMaker's syntax. It creates a series of 10 new order records.

 

 NewOrdersBatch Set Field [ Invoices::gLoopCounter; 0 ] Loop     Set Field [ Invoices::gLoopCounter; Invoices::gLoopCounter + 1 ]     Perform Script [ "__NewOrder" ]     Exit Loop If [ Invoices::gLoopCounter = 10 ] End Loop 

This simple example demonstrates all the essential logic for working with loops. First, some condition by which the script exits the loop must be established. In this case a hard-coded number (10) is used to exit the script.

Second, notice that a field was created to keep track of the iterations through the loop. Often called a loop counter , it is initialized (set to an initial value) just in case it was left at some different number from another script or, as is the case here, at the end of this script. An improper starting condition for a loop is a common source of bugs .

Third, the counter is incremented as you go. A loop exit condition is almost always useful only if something changes during the course of a script. (It's possible you might be sitting in a loop, waiting for something elsewhere to change and checking periodically, but this kind of "polling" activity is not commonly needed in FileMaker Pro.)

Notice too where the commands are placed. It is not until after the __NewOrder script is performed that the exit loop condition is tested . This ensures that the script does, in fact, run 10 times. If the __NewOrder script were placed below the Exit Loop If step, this script would still be perfectly valid, but it would generate only 9 new orders.

Loops get more interesting when combined with conditional logic more complex than checking for an incremented counter. The first example for closed invoices did just this. It is possible to build a loop that tests for certain conditions within your system and exits only when those conditions are met ”for example, a loop that processes all unclosed invoices, checking at the end of each cycle whether it has reached the end of a found set.

Loops can be exited in a variety of ways. The simple conditional in the script example shown earlier is quite common. Another common technique is to use the Go to Record/Request/Page [Next, Exit After Last] script step. It enables you to step through a found set and exit a loop after the last record is reached.

Another way to exit a loop is to exit or halt the script altogether. You have two processes running: the script itself, which can be terminated , and the internal loop.

graphics/troubleshooting_icon.jpg

To cope with endless loop problems, refer to "Testing Loops" in the Troubleshooting section at the end of this chapter.


Working with Custom Dialogs

One of the most common user interactions necessary for a system is to capture a response to a question. "Are you sure you want to delete all records?" "Do you want to report on all records, or just your found set?" "Would you like fries with that?"

The Show Custom Dialog script step is a great, built-in way to capture this sort of interaction. (There are ways to create layouts that act and behave like dialog boxes, but they're a good bit more work.) Custom Dialogs allow you to present some descriptive text or a question to a user and capture a response (see Figure 9.8).

Figure 9.8. Here's an example of a custom dialog. Notice that it has an appropriate title and specific, data-derived text.

graphics/09fig08.gif


To learn how to create pop-up layouts that behave as modal dialogs, see "Multi Window Interfaces," p. 367 .


Naturally, after you've created a custom dialog, you then need to deal with the results. FileMaker Pro stores the user's button choice until the end of the current script or until you present another custom dialog. Think of these dialogs as existing solely within the space of a given script.

To identify which response the user chose to your dialog, use the Get (LastMessageChoice) function. This function returns a 1, 2, or 3 based on which button was clicked, from right to left. The right-most button is identified as 1. The label you assigned to the button is not consequential.

Conditional scripting similar to what was covered previously allows you to test the choices a user made and respond accordingly . Here's an example:

 

 Report_Revenue_Start Show Custom Dialog [ Title: "Revenue Report"; Message: "Do you want to view a Revenue  Report by month, year, or a date range?"; Buttons: "Range", "Year", "Month"; Input #1: Invoices::Date_Range, "Date Range (e.g., 1/1 graphics/ccc.gif /2004...2/15/2004)" ] If [ Get (LastMessageChoice) = 1 ]     Perform Script [ "__Report_DateRange" ] Else If [ Get (LastMessageChoice) = 2 ]     Perform Script [ "__Report_YearSummary" ] Else If [ Get (LastMessageChoice) = 3 ]     Perform Script [ "__Report_MonthSummary" ] End If 

Custom Message dialogs can also be used to guard against data problems and help offer users a somewhat richer data entry process. Figure 9.9 presents an idea of what this might look like. Instead of going with FileMaker's standard "Revert Field" response to a validation error, you might instead want to build a script that checks your data either on demand or as part of a scripted data entry routine. This completely skips the standard field validation options in FileMaker and instead offers users the chance to correct their data in a dialog. Keep in mind that they'd need to perform this script somehow.

Figure 9.9. This custom dialog offers a graceful alternative to FileMaker's native validation dialogs, but would need to be prompted by a script.

graphics/09fig09.gif


Here's an example of how you might handle validation in a scripted way:

 

 Validation_Prompt # # Assume this next step checks some condition and sets the gInvalidFlag # to a value if there is an error.     Perform Script [ "__Validation_Check" ]  #  If [ Invoices::gInvalidFlag > 0 ] # # Notice in this next step that a case statement analyzes the error message # passed to it.     Show Custom Dialog [ Title: "Shipping Correction"; Message: Case (Invoices::gInvalidFlag = 1;     "You have entered a shipping date that precedes order fulfillment. Please enter a corrected ship date.     Order " & Invoices::Order_Number & "Date to be fulfilled: " & Invoices: graphics/ccc.gif :Order_Date_Fulfillment;     Invoices::gInvalidFlag = 2;     "Your ship date cannot be more than 14 days past your fulfillment date. Please enter a corrected ship date.     Order " & Invoices::Order_Number & "Date to be fulfilled: " & Invoices: graphics/ccc.gif :Order_Date_Fulfillment;     Invoices::gInvalidFlag = 3;     "Your ship date is set for the same day of fullment, but this is not marked as a rush order. Please enter a corrected ship date.     Order " & Invoices::Order_Number & "Date to be fulfilled: " & Invoices: graphics/ccc.gif :Order_Date_Fulfillment;     "The system has posted an invalid internal error message [error code: " &  Invoices::gInvalidFlag & "] ; please contact the database developer, and reference the 'Validation Prompt' script routine. We apologize for the inconvenience."); Buttons: "Done", "Edit Order"; Input     #1: Invoices::Order_Date_Shipping, "Ship Date" ]     If [ Get (LastMessageChoice) = 2 ]         Perform Script [ "__Edit_Order" ]         Exit Script     Else         #         # Here we're employing some recursion. After the user inputs a new Ship Date, we'll run this script again until it validates. Notice that the exit condition is an error message of < 1 at the top of the script. The inner IF statement will only proceed if gInvalidFlag >0.         Perform Script [ "Validation_Prompt" ]         End If End If 

A better way to handle this script would be to better abstract your error messages and conditions. Imagine a table of error ID numbers followed by explanation text. Simply reference a table of related values, and the very long, hard-coded case statement goes away.

Custom dialogs are fairly flexible, but they do have limitations. The most obvious limitation is that their appearance cannot be altered . In a FileMaker layout you're able to apply images, background color fills, and other graphical attributes of the screen. Not so in a custom dialog. You are limited to a system-style dialog.

Second, and more importantly, if you provide input fields (as was shown in Figure 9.7), data entered is posted to your database only if the user clicks the first, right-most button in the dialog. You do not have programmatic control of the input field behaviors. This then means your users will have "post to database" as their default. Not optimal, but there you have it.

The third limitation of the dialog lies in scope: You're limited to three input fields and three buttons. If you need anything more complex, you need to use a standard FileMaker layout to build a custom pop-up layout.

TIP

One alternative to keep in mind is a range of plug-ins available that also offer dialogs. Visit FileMaker's Web site to explore those options.


 <  Day Day Up  >  


QUE CORPORATION - Using Filemaker pro X
QUE CORPORATION - Using Filemaker pro X
ISBN: N/A
EAN: N/A
Year: 2003
Pages: 494

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net