Jump to content
View in the app

A better way to browse. Learn more.

FMForums.com

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

So, I have a nice layout (let's call it Person_Details) that contains all the fields in a People record.

And I have a script (let's call it Open_Person_Detail_Window) that creates a new window containing this layout. Encapsulated here, like the contents of a black box, are the things I want to always happen when displaying this window: Zoom=100%, View=Form, Hide Status Area, Resize To Fit, and Moving the window to the center of the screen. It's nice having one script to encapsulate these invariant details.

This layout is so nice, however, that it's awfully tempting to want to use it, not only for editing an existing record, but for adding a brand-new record and even for entering Find criteria. The way layouts have always been intended in FM.

And of course there are a wide variety of places throughout the user interface that I might want to pop up this lovely window. For instance, I have a layout that shows a list of People - and I want to allow the user to click an Edit button next to one of the names, and have that drive Open_Person_Detail_Window to pop up the detail window. Or, there's a Script Menu item called "Add Person", and I'd like for that to somehow dovetail into Open_Person_Detail_Window, only this time with a freshly-created record. Or, a "Find Person" command that, again, leverages Open_Person_Detail_Window to handle the invariant issues of displaying the Lovely Window, but this time with a Find request.

Or, suppose I have a Club Details layout, with a portal to various People who hold administrative positions at the club. From that layout, I might like to be able to click on a name in the portal and - bang - get the Person Details window.

Let me try asking my question this way: assuming that other people have grappled with trying to write well-factored, reusable, modular scripts in FM, how would you design Open_People_Details_Window (the in/out parameters, its internal functionality, and how to use it)? Are there any "rules of thumb"?

I've worked on this posting for an hour and a half, and I hope it's not complete gibberish. Thanks for any thoughts you have, or requests for clarification.

Chap

You might want to consider a pile of utility scripts:

Print Legal Portrait

Print Letter Portrait

New Window

New Record

Search

Go to Layout A, B etc.

Adjust Form

Adjust List

etc

Then you are plugging in subscripts made up of the utilities:

Script:New Record for A

New Window

Go To Layout A

Adjust Form

New Record

Script: View Layout A

New Window

Go To Layout A

Adjust Form

Script: Search Layout A

New Window

Go To Layout A

Adjust Form

Search

You can take it as far as you like, but the idea is to make everything modular and reduce scripting overall.

Speaking in general, you'll want to look towards utilizing script parameters, variables, conditional statements, and what not in how your scripts are written. Most importantly, you'll want to break down and essentially atomize your entire script library into as many isolated yet distinctly unique and interchangeable sub-script units possible. This will help modularize any/all of your scripts for successful deployment across a greater variety of contexts.

I was in a somewhat similar situation with a Filemaker DB I designed for a private security firm, where I wanted to keep as much of the relevant information and necessary functionality streamlined around 1-2 primary layout interfaces—instead of ferrying the user around to various layout screens to carry out this or that task, etc. Far less confusing for end users that way and often simplifies the overall development process (though sometimes it can be a major headache too).

For what I did, most of the action centered around an "Incidents" layout—a list view of incidents/call reports sorted by received time. So as patrol reports, noise complaints, domestic violence calls, etc. would come rolling in over the course of the night, one could easily observe all of this at a glance. All searching and printing was set up to be conducted from this interface as well. When opening a particular call in the list to see more detailed information, a new window would popup displaying the 'Report' layout. Therein would be timestamps of the officer's on-scene and departure times, a short write-up of all relevant whos, whats, whens, wheres surrounding the event, the outcome of said event, etc. Ultimately, 99% of the time these two layouts were literally the only ones the user saw and interacted with.

Now to the point of why I'm explaining all of this… In my example, there were 3 (technically 4) different ways to open a given call, but only 1 script ('OpenCall') ever did the actual opening. The actual script is as follows:

• Allow User Abort [Off]

• If [Let([$open_recs=WindowNames(Get(FileName));$curr_rec=Evaluate($$Win_Title[2])];FilterValues($open_recs;$curr_rec))]

• Select Window [Name: $curr_rec; Current file]

• Else

• Go to Related Record [From table: "bla bla"; Using layout: "Record"…]

• End If

You can ignore my convoluted looking calculations for now: The crux here is that 'OpenCall' by itself is inert—it never does anything except as a sub-script of other scripts. The 2 main ways it could be activated are:

1) User double-clicks a call in Incidents

2) User presses Enter/Return while a call is selected in Incidents

Event #1 activates a script called 'DoubleClick' (by way of a button). It looks like:

• If [Let([$rec=Get(RecordNumber);$$RecID=If($rec≠$$RecID;Get(RecordNumber))];not $$RecID)]

• Perform Script ["OpenCall"]

• End If

Event #2 activates an OnLayoutKeystroke script trigger that contains this conditional argument:

• If [Let([$k=Code(Get(TriggerKeystroke))…]

• Else If [FilterValues($k;"10¶13")]

• Perform Script ["OpenCall"]

• End If

• Exit Script [Result: 0]

Another way 'OpenCall' is brought to fore is when making a new record by way of the 'NewCall' script:

• Allow User Abort [Off]

• Freeze Window

• New Record/Request

• Perform Script ["SetWindowTitle"; Parameter: 1]

• Commit Records/Requests…

• Perform Script ["OpenCall"]

The script step above involving 'SetWindowTitle' provides a good segway on another option(s) you can employ to increase modularity in your scripts: parameters and global variables.

In this same example, there is a 'Variables' sub-script set to run as part of the main file startup script. One of its script steps sets a 5-repetition global variable $$Win_Title. Each repetition of $$Win_Title is a string literal for use in the 'SetWindowTitle' script. The 'SetWindowTitle' script itself only constitutes this 1 line:

• Set Window Title [Current Window; New Title: Let([$param=Get(ScriptParameter);i=GetValue($param;1)];Evaluate($$Win_Title))]

Usually this would run as a sub-script of an OnLayoutEnter script trigger, or as part of some specific mode/feature on that layout, etc.—hence dictating the supplied parameter. An OnLayoutEnter script trigger for "Incidents" could run 'SetWindowTitle' with parameter=1, setting the window title to the value returned by Evaluate($$Win_Title[1]). You may have noticed too that the same script and parameter is a sub-script of the 'NewCall' script mentioned above; this is because $$Win_Title[1] contains a Get(TotalRecordCount) calculation that appears in the window title for that layout. Similarly, the OnLayoutEnter script for "Report" could run 'SetWindowTitle' with parameter=2, yielding a value returned by Evaluate($$Win_Title[2]). So on and so forth. This approach is nice, as it allows the same simple script to be used and re-used for setting the title of a window whenever and wherever necessary. Further, if when retooling the general appearance of all window titles throughout, it can be done from one location instead of having to individually modify a slew of separate scripts.

Okay, enough writing for me. Hope this gives you some ideas.

I started using modular scripts a few years ago FM vers 6 but stopped doing so because at that time it was more trouble than it was worth, the problem was it's very tempting to edit a script at a later date for whatever reason and forget that that script was used elsewhere and something breaks. I tend to make heavy use of copy paste now.

Now we have folders in script manager this probably isn't a problem as you could organise your "modular" scripts in folders labelled as untouchables. still it's something to be aware of.

It's a nice idea but I do not see any advantage except to maybe save a couple of kb disc space.

I am fairly sure that someone wrote a large article about this subject in the last year or so, not sure if it was in this forum or not.

  • Author

It's going to take me a day or two to absorb all this, but I wanted to gratefully acknowledge your contribution. You've definitely given me some useful ideas, like subscripting global variables and using the Evaluate function. Will post more to this thread later, but thank you for taking the time to share your ideas.

  • Author

I'm curious, Ashton: what's going on in this line of code?

If [Let([$rec=Get(RecordNumber);$$RecID=If($rec≠$$Rec ID;Get(RecordNumber))];not $$RecID)]

(I assume that $$RecID has nothing to do with the result of Get(RecordID)?)

It is the double-click handler; but a space has worked its way into the second instance of $$RecID that doesn't belong there. Should be like this:

If [

Let([$rec=Get(RecordNumber);

$$RecID=If($rec≠$$RecID;

Get(RecordNumber))];

not $$RecID)

]

Create an account or sign in to comment

Important Information

By using this site, you agree to our Terms of Use.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.