Writing JavaScript in FileMaker is hard. Sure, the path is easy to see and clear to follow, but the actual writing of the code is hard. I have tried to find a way to write JS code that makes it fairly easy. And by “easy,” I mean “make it so that FileMaker developers don’t have to learn a hundred skills to get JS to work in FM – other than the JS itself.” I’m striving for a better JavaScript Development Environment.

An Okay JS Development Environment

My first attempt was writing or placing code in FileMaker fields. That worked…and it didn’t. There’s a lot of advantages to this method, but there are as many disadvantages (a fact I was reminded of in session feedback comments and emails about the demos I’ve released). We’re just writing in a text field – there’s no automatic formatting of the code, and there’s not any helpful type-ahead or auto complete features. There’s a lot wrong with this. Even my attempts to use a code editor JavaScript library to render the code from a text field proved only marginally better.

I continued doing this method many times (here, here, and here) always knowing that this isn’t ideal.

But recently, Kevin Frank approached me about a JS project. Working with him on this JSON-parsing library, I took it as an opportunity to finally come up with a better way of developing JavaScript in FileMaker. Kevin has written about it in his post FileMaker 19 + JSONata. Check out the details of the origin and use. We also recorded a podcast episode about it – check that out.

Towards a Better JS Development Environment

After all of our work with JavaScript in FileMaker, we’ve come to our current definition of a better JS development environment. To be effective with our coding time, here’s what a ‘better development method’ must include:

  1. Using a proper HTML/JS code editor.
  2. Immediate rendering or performing of the code in the FileMaker web viewer object.
  3. Using data from the FileMaker app.
  4. Using the result of the JavaScript processing in FileMaker.

Let’s tackle each one of these and use my work with Kevin as illustration.

A Proper Editor

Writing JavaScript is a piece of cake when one has an integrated development environment (IDE) that catches all the mistakes and properly formats the code immediately. And my previous methods (e.g., typing into a text field) failed on both those fronts. Sure, I could use a JS code-editing library (I’ve done that). It works decently, but there’s always a catch or two that frustrated users (including me).

So this trend toward the better includes using a proper IDE to write the JS outside of a FileMaker field.

Working with a proper editor brings up a whole host of challenges; one has to actually pick a platform to use and then learn to use that platform. That takes time. I use VSCode for all my JS work now (and from that app will come screenshots). It’s complex and I don’t know all of it. But what I do know is that it makes writing JS so much easier. 

With this project, I set up a small web-based file structure inside a project folder. There are two simple files in which I do all my writing: index.html and index.js. That’s manageable. I can write my simple JavaScript code here and (eventually) get it into FileMaker.

index.html
index.html
index.js
index.js

I can’t get into all that VSCode does here in this post, but if you’re going to explore writing JavaScript, VSCode is a great choice to use. I’ll share more about how to use VSCode in the near future.

See the Fruits of My Coding

The FileMaker developer is used to seeing what she is developing appear or work before her eyes – if not in scripts, at least in what’s on the layout. So too must she be able to see the code work (or not) in the web viewer right away. Additionally, since we’re using the web viewer inside FIleMaker, it’s essential to get the JS code inside FileMaker as soon as possible.

Todd figured out a way to see the JavaScript work immediately in a FileMaker file’s web viewer object. We use it in our projects here at Proof+Geist, we used the technique in the add-ons, and I’m using it for this demonstration file.

Essentially, when I am developing the JavaScript code, I can run a development server that serves the code I’m writing. This development server is picked up by the web viewer and shows the results of my JavaScript coding. Whether the code works or doesn’t, I see how my code is turning out immediately.

By starting up a development server in VSCode, whatever I write in the code will be picked up by the web viewer.
The Development Server in Action

The mechanics behind this are a bit complex. It involves Node.js and some JavaScript libraries to run a development server. Hopefully, very soon, we will have a template project you can use that has all this already set up.  So be on the lookout for that.

Using the web viewer inside of FileMaker to render the code is one part of a better JavaScript development environment.

Using FileMaker Data

A hallmark of a better JavaScript development environment is to use real data inside FileMaker. Since we’re working inside a FileMaker app, it follows that we could use the data already in there. I don’t want to develop with fake data that may not have the same performance considerations as the real data. If my goal is to show 1000 records in a data table, then I want to make sure the whole process works with 1000 real records. 

In our development, we use data from FileMaker, and we do this using the Perform JavaScript in a Web Viewer step.

For this JSONata example, I’m using this script step to load data into the web viewer. The web viewer already contains the JS code, and the work will happen when it receives the JSON data and the query. Here’s my code.

This pattern is pretty standard:

  1. The web viewer on the layout is named. I write the name into a variable (line 1).
  2. I give the name to the global function inside the JavaScript in a variable (line 2).
  3. I pick up the query data in a variable (line 3).
  4. I pick up the JSON data in a variable (line 4).
  5. I then call the script step with the above pieces (line 8).

Notice that I’m pausing in line 7. In all of our work with the web viewer, we’ve found this to be essential. Since I’m using a new window (line 5) where the web viewer is located, I need to wait a small amount of time for the web viewer to load. And this has to happen so that the JS function “simpleQuery” is loaded and ready. Between Kevin and myself, we’ve tested it to be around ½ to 2 seconds. 

Getting the Data into the Web Viewer

The JavaScript function itself is pretty simple, but it has one part that is vital: it has to parse the incoming JSON data into something JavaScript can read. Line 4 here shows that I’m taking the JSON that comes in and parsing it.

The simple function called from FileMaker

We have template scripts written to help us remember the pattern. I use those all the time. 

Returning Results

Many times the point of a JavaScript library is to return results to FileMaker. This is the case in the work Kevin Frank and I did together. He found this cool library called JSONata that parsed JSON using a query language (one designed for this library). The idea is to pass the web viewer some JSON and a query and then get the result of the query back. So we have to work with FileMaker’s ability to get the result out.

In this example, we’re getting the results back in two ways: 1) we’re setting the data into a field, and 2) we’re getting the data back to use inside the script itself.

You can examine each script to see what they’re doing. They’re pretty simple:

Get Result Into the Field

This script simply shows what happens in the normal use case: One script calls the JavaScript. The JavaScript does the work and calls a FileMaker script – in this case, “Get Result” to return the result back to FileMaker. The original calling script finishes its run before the “Get Result” function runs. And that’s a fine progress of steps. The callback script gets the result and places the result into a field. End scene.

Get Result Into the Script

This script is built differently and uses the newer FileMaker.PerformScriptWithOption() function (documented here). In this case, I want to use the result in the original script. So I call this the function simpleQueryInScript(). The function processes the JSon using the query and calls back to FileMaker a script called “Get Result In Script”. This script interrupts the original script, gets the result from the JS and, in this case, sends it back to the original script.

I know this is a lot to take in, so study the scripting and examine the JS code provided here and see how it all works together.

This is a better environment for JavaScript in FileMaker development. It’s pretty close to all we can do to make it easy enough to write JS and see it render out in the web viewer while developing.

One more thing

We’ve been talking here about writing JavaScript. But there’s one more step: actually using the code you’ve written in an actual production. Don’t worry. We’ve got that covered. After I’ve finished with the code, I can run a small command and the JavaScript is put into the correct field inside of the app for the web viewer to pick up.

Uploading new code to FileMaker

Onward

Finding a better JavaScript development environment for FileMaker has been something we’ve explored for many years. We’re interested in making using JavaScript even more accessible by providing easy tools to get the job done. This FileMaker 19 + JSONATA exercise gave me the opportunity to flesh out what is really necessary to easily develop the code. Thank you to Kevin Frank of FileMaker Hacks for his proposal, his collaboration, and his support.

We’re not done; in future posts, we can point out how we work with VSCode and other tools to make this work.

If you are interested in working more with JavaScript in this better environment, let me know (jeremy.brown@proofgeist.com). If there’s enough interest, we can provide some training around this environment set-up and use.

The demo file is found here and at Kevin’s site.

The FileMaker JSON functions we have in FileMaker 16 have changed the development game for many folks. JSONSetElement, JSONGetElmeent, JSONDeleteElement, JSONListValues, JSONListKeys are powerful functions that let us collect data into an object, to parse data from an object, or to edit the object itself. We can even format a JSON object using JSONFormatElements. Since JSON’s purpose is to exchange data, it seems these functions are good enough. We at Geist Interactive have combined these with other FileMaker functions to produce some custom functions (in JSONAdditions.fmp12)  that are useful in many circumstances. Our custom functions actually manipulate the JSON in some way, doing just a bit more than the native functions. In this post, we’ll take a look at a FileMaker filtering JSON function: JSON.FilterByExpression.

You can follow along with this download here.

Simple & straightforward

This is a simple custom function. Its purpose is to return the elements of an array that satisfies an expression. Here’s the syntax:

JSON.FilterByExpression( array ; expression)

You simply pass in it an array and an expression (in quotes), and this custom function returns those elements in the array that satisfy the expression.

The expression is the key. You write an expression that can be used to check a value of a key in each element of the array. Those elements that have have values that meet satisfy the expression are returned.

Let’s apply this custom function to an example, starting with the use case.

Use Case: Given an object returned from the client’s shopping cart website api, chart any number of years’ unit sales. Give the user the ability to choose the start and end year, and display the units sold for that year range on a chart.

Here’s the “sales” array returned from the api and placed into the field: shoppingCart::JSON

{
"sales" : [
{
"year" : 2011,
"units" : 43
},
{
"year" : 2012,
"units" : 22
},
{
"year" : 2013,
"units" : 100
},
{
"year" : 2014,
"units" : 2
},
{
"year" : 2015,
"units" : 12
}
]
}

JSON.FilterByExpression can easily parse through this array and return those elements that are within the boundary years.

JSON.FilterByExpression ( 
JSONGetElement (shoppingCart::JSON ; "sales")  ;  
"JSONGetElement ($item ; \"year\") ≥ 2012 and JSONGetElement ($item ; \"year\" ) ≤ 2015 
)

Will return

[{
"year" : 2012,
"units" : 22
},
{
"year" : 2013,
"units" : 100
},
{
"year" : 2014,
"units" : 2
},
{
"year" : 2015,
"units" : 1
}
]

The FileMaker filtering JSON custom function is recursive. It will loop over all the elements in an array and construct a new array of those elements that agree with the expression

Express(ion) yourself

The goal of my custom function is to return those elements that have years between 2012 and 2015 inclusively. So that’s how I wrote the expression:

"JSONGetElement ($item ; \"year\") ≥ 2012 and JSONGetElement ($item ; \"year\" ) ≤ 2015"

Notice a few things:

  1. The FileMaker expression must be quoted.
  2. The expression will be applied to each element in the array
  3. The variable $item will contain current item in the array. (Kind of like the current record when looping records.)
  4. I’m using “JSONGetElement()” function to pull the ‘year’ value.
  5. Since the expression is quoted, I’m escaping the ‘year’ key.
  6. I’ve got two parts to my expression in this example. But any expression and any combination of expressions can work.

Here’s what my expression is saying:

For this object in $item, check to see if the value in the key “year” is greater than or equal to 2012 and less than or equal to 2015.

As this FileMaker filtering JSON custom function loops through all the elements in the array, it checks: Does the value in “year” satisfy this expression? If so, add the element to an array.

Finishing the use case

Once I’ve gotten back the array elements that satisfy the expression, I can use another custom function: JSON.GetValuesAtPath (array ; path) to return the “units” values. I’ve done this before in another charting exercise. We will look at this function in a later post.

The full calculation to pull filtered values from an array.

And thus, the chart is born. (Well, there’s a little more to the chart, but you can view that in the sample file).

filemaker json chart

The chart generated using the JSON.FIlterByExpression

The JSON Structure

We got an email of someone struggling with this custom function. It returned a “?”. After examining the person’s data structure, I realized what he gave us wouldn’t work. It looked like this:

{"2012": [
{
"value": "22"
}
],
"2013": [
{
"value": "100"
}
]
}

The structure, besides being valid though unnecessarily complex, doesn’t contain an array of objects that the custom function JSON.FilterByExpression can loop through. Here the year is the key to a one-element array of one JSON object containing one key/value pair. This is an object. It is not an array, so our custom functions wouldn’t work.

By the way, this makes me wonder: what is the ‘proper’ structure for JSON and data. I will have to explore that.

Our custom functions work with arrays. Specifically, the custom functions loop through the elements of the array and returns a new array or list.

But that’s okay. Our custom functions work with VERY COMMON JSON data structures. Often an api will return arrays within the entire object, just as we see in the working example above. If we can drill down and grab an array from the object, we can use these custom functions.

New tool: FileMaker Filtering JSON

It is wonderful that we now can natively work with FileMaker filtering JSON to gather records into an object, to parse api results, and to manipulate and configure the JSON. We’ve just added a few more we find useful.

Give our JSONAdditions file a try. There’s some useful custom functions that will further your ability to not only generate data into a JSON object, but also to filter, merge and otherwise manipulate an existing object.

If you do adopt these into your own solution, I recommend simply copying / pasting all the custom functions into your file; many of these need other custom functions.

Go forth, now and expand your FileMaker JSON toolset.

If you didn’t download it before, take a look at the sample file. It uses the chart object in FileMaker.