Patterns of JavaScript in FileMaker

Everytime I create a JS integration, whether in the training or for a client, I use the same bits of code over and over. These patterns are found in both the FileMaker scripting and the JavaScript. In this post, I illuminate the patterns that I use all the time.

When I taught 5th grade math, I had my students practice certain skills many times. Whether using hand gestures, working with manipulatives, or repeating text written on a worksheet, I followed the idea that some neurons can be created and connected with that repeated practice. So this is just another way. Read through these patterns and see it in action in the code and in videos and sample files.

To be clear: I always follow the below patterns; there are other ways to handle the same use cases, but these are what I'm now used to and evangelize.

Use Case: Loading the web viewer

It's vital to get the code into the web viewer so that it renders what we've worked on, and, of course, so the client can see the data they're interested in. Somehow we have to control the web code getting loaded in, and this is the pattern I use:

Pattern: Load the code via a script

In my work, the HTML is stored in a field, probably called "HTML" in an "HTML" table (original, I know). In a script called "Load Web Viewer", one of the steps fetches the code from that field into a variable. Further down the script, the code is placed into the web viewer on the layout. Then the script pauses for a short amount of time.

After the short pause, the script continues. I have found this indetectable pause is necessary because it gives the web viewer a chance to 'breathe', to make sure all the code is loaded for the rest of the script. It may not be anymore, but I have the pause step still, and probably will continue to use it.

It's important to understand that the code is loaded into the web viewer, but nothing is rendered yet. The render comes in the next pattern.

Loading the JS with a FileMaker script As part of my JS Dev Environment, I load the code from either the field or from the dev server that's running. You can see that in step 5 above. This allows me to write the code and see the fruits of my writing render immediately in the web viewer.

So this is the first pattern I work with all the time. Let's explore other patterns.

Use Case: Rendering the UI

So the code is loaded into the web viewer. The pause happens. While this is happening, the web viewer is still blank. Finally, the controlling script causes the library's UI to be rendered on the layout.

Pattern: Load the UI via the script

The FileMaker script includes the "Perform JavaScript in a Web Viewer" step. This is the trigger that tells the JS to execute the code that renders the UI. All of the JavaScript that renders the interface and interacts with the data in any way is inside the function called by this script step. Here's what it looks like: The JS Code inside of the function called by FileMaker

In the code above, the function starts at line 6. It's called "loadData" and it is placed on the browser window with the keyword "window.". Anything inside this function (blurred out to empahsize the function itself) is executed.

Use Case: Loading data into the web viewer

Obviously the purpose of the JS widget is to display data in some form: a chart or a datatable, or a date picker. So we need to load the data in.

Pattern: Pass data as a parameter

That same script step used to cause the JavaScript to render its user interface will pass data in as a parameter to the function. All JS functions (and, indeed all FileMaker scripts) can receive something as a parameter. The FileMaker script called "Load Webviewer" (in the image above) contains a subscript call that goes and gets the data. The data is brought back here to the main script and placed inside an object with the "data" key. Finally, that object, in the $json variable, is used as a parameter in the Perform JS script step. Passing data in an object to the JS Again, this pattern I use over and over. I choose to put all my parameters into one object inside the $json variable. I could pass in multiple parameters, as the "Parameters:" section of the options shows, but I like to place all the parameters into one object and pass that one object in. This gives me the flexibility of simply pasting this script step into the next script and adjusting the variable upstream.

Use Case: Prepare the FileMaker data for JavaScript

The one thing we have to do in the JavaScript is make what comes in from FileMaker usable to the library. A JSON object passed to the JavaScript is really just a string of text. JavaScript doesn't know how to work with a string that looks like an object, so there we need to convert the JSON/string into a JavaScript object.

Pattern: Convert the string to a JS object

Luckily JavaScript can handle it. Here's the pattern I use:

window.loadData = function (json) {
  const obj = JSON.parse(json)
}

The middle line there, the JSON.parse() function takes the FileMaker-string-that-looks-like-a-JSON-object and converts it to a JavaScript object for further use in the code. This simple, one-line pattern, is used all over

Use Case: Sending data back to FileMaker

Since interaction with the interface is a cruical feature for any app we build, we have to consider how this is done using JavaScript. As with the other patterns, this requirement is hardly a problem.

Pattern: Invoke a library's onclick event & trigger FileMaker to receive the data

Every JavaScript library has what is called an 'onclick' event. This is exactly what the term suggests: when a user clicks on something–be it a row or a bar or a field–the library will send what was clicked on back to the browser. Here's what the C3 charting library's onclick event looks like:

window.loadChart = function (json) {
  const obj = JSON.parse(json)
  const data = obj.data

  const chartOptions = {
    data: {
      columns: data,
      onclick: function (d) {
        //here is the function that runs when I click on an bar or a data point in the chart.
      },
    },
  }
}

Inside of this 'onclick' option (see the C3 documentation) we have the function that will take the data from the chart set into the d variable and send it to FileMaker. Here's how:

onclick: function(d) {
  const str = JSON.stringify(d)
  FileMaker.PerformScript ("Chart OnClick", str)
}

the const str line takes the data coming from the click and transforms it back to a string so that FileMaker can read and use it. The FileMaker.PerformScript() line refers to the function inside the FileMaker library that is injected into the web viewer when we load code into it. This injection comes from the FileMaker Pro app; it's nothing we can control.

This function takes two parameters: the FileMaker script name and the data we want to send back.

When the user clicks on the data point in the chart, the JS will trigger this function to run. The FileMaker script in the parameter space will trigger and it will take what's in the str variable and pass it to the script as Get(ScriptParameter).

Pick up these Patterns

Working with JavaScript in FileMaker is a lot like working with FileMaker in FileMaker: You learn the patterns and use them over and over. Over a small bit of time these become rote and boring; you can copy them from one project to another or build them into a template to use over and over. Here are the patterns again:

  1. Load the code via a script.
  2. Load the UI via a script.
  3. Pass data as a parameter.
  4. Conver the string to a JS object.
  5. Invoke a library's onclick event & trigger FileMaker to receive the data.

The patterns described above, when internalized, will make your work with JavaScript in FileMaker so much easier and rewarding.

So give it a try. Start with the JS Dev Environment and work to integrate some JS library into your app. If you're interested in learning more about these patterns and get practice/guidance in using these patterns, join one of the upcoming training courses. We'll work with and explore deeper these patterns. Feel free to ask questions about this post over in the JS-in-FM Community.