Web Viewer Tips For FileMaker 19 – Hardening the FileMaker.PerformScript Function

If your web viewer code calls the FileMaker.PerformScript function when loading, it’s possible that it hasn’t been injected into the web viewer yet, and your code will fail with a breaking error. How can we harden our opening routine to ensure this breaking error doesn’t occur and provide the best experience for the user?

Part 3 of 3 of our series on Web Viewer Tips for FileMaker 19.

In a previous post on Web Viewer Tips we discussed how the new version of DayBack uses a familiar JavaScript and API pattern and the benefits of doing this. In this post, we’ll suggest bringing another common JS pattern into your app: try-catch.

FileMaker 19 Web Viewer Calendar
DayBack gets FileMaker data (Events and To-Dos) as part of its loading routine.

“Can’t Find Variable: FileMaker”

The web viewer will initiate making calls to the FileMaker file via the FileMaker.PerformScript function as the web viewer loads, but since FileMaker is also injecting the FileMaker.PerformScript function into the web viewer as it loads, it’s possible that the function hasn’t been injected before your code calls it. This is part of the asynchronous nature of JavaScript, sometimes the FileMaker.PerformScript function is there in time, and sometimes it isn’t. When it isn’t there, the error “Can’t find variable: FileMaker” is thrown. This is a breaking error, and your JavaScript will stop executing on the offending line.

In most situations, we can trap for this kind of error by testing for it in a simple If statement, something like:

If ( FileMaker && FileMaker.PerformScript ) {
   FileMaker.PerformScript ( 'some script' , 'some parameter');
 }

However, this does not help and you’ll still get the “Can’t find variable: FileMaker” error even when referenced in the if statement and the code breaks.

Using Try-Catch Blocks

Using Try-Catch blocks is a more robust way of trapping for errors and exceptions in JavaScript. All code run within the Try block will complete even if there is a potentially fatal error. Instead of the error being reported at the browser level, it will be sent to the Catch block as its argument. Here’s an example where the alert function is misspelled.

try {
   alret(‘Hello World’);
 }
 catch(e) {
   console.log(e.message);
 }

If the “alret” function is called outside of the try block, then this error would break our code and halt its execution at the line. By wrapping it in the try block, the code will continue safely and pass the message to the console log.

Since we know the FileMaker.PerformScript function will eventually be injected into the web viewer, we’re going to use the try-catch blocks to simply retry the routine a few times so that the injection can catch up with our code. This is the function we came up with, and even though it’s only on web viewer load that we’re worried about the failure, for consistency’s sake, we use it for all our calls to the FileMaker file.

function fileMakerCall(payload, retry) {

  //payload argument contains the script name
  var script = payload.script;

  //initialize the retry argument if empty
  retry = retry ? retry : 0;

  //number of times to retry before reloading the page
  //we've only observed the need for one retry befor FileMaker.PerformScript is there
  var numRetries = 5;

  //stringify the JSON payload for fileMaker
  var payloadString = JSON.stringify(payload);

  //begin try-catch
  try{
    FileMaker.PerformScript(script,payloadString);
  }
  catch(e){
    //try has failed re-run on a half second timeout if it hasn't been attempted too many times
    //enable for testing and debugging
    //console.log(e);
    if(retry < numRetries){
      setTimeout(function(){
        fileMakerCall(payload,retry);
      },500);
    }
    else{
      //too many retries, reload the whole page
      //although we've never needed this
      location.reload();
    }
  }

}

As you can see, the function will try to call FileMaker.PerformScript again up to 5 times. We don’t want to get stuck in an infinite loop, so providing a maximum number of retries is certainly a best practice, although I’ve never seen more than 1 retry be required for the FileMaker.PerformScript to be there and for the try block run without passing the error to the catch block. At the worst, users may experience a half-second delay during the loading routine instead of simply failing and needing to manually reload the web viewer.

Conclusions

The asynchronous nature of JavaScript can create timing issues. Although this error may seem particular to FileMaker and its web viewer, similar issues have existed for web developers for years:  so have the solutions they’ve come up with to handle them. JavaScript may feel new to many of us in the FileMaker world, but we can take comfort that there’s a wealth of experience out there that we can adapt to our solutions. If you encounter similar JavaScript issues with your web viewer apps, even though the exact terminology may be different from what we’re now doing in FileMaker, someone has likely solved the issue. Some googling and searching through Stack Overflow will likely provide the solution.

Featured Posts

Follow Along

Stay up to date with the latest news & examples from SeedCode

10 Comments

  • Andreas Thyholdt

    Thank you so much!
    After hours of frustration, this function saved the day.
    Don’t know why, but FM 19.6.3 persistently failed to inject it’s code on even the simplest WebViewers today and this solution was the only one I’ve found that worked reliably.

  • Max

    I just found your article because I’m having a similar issue. Thanks for sharing your solution. Very helpful!

    Unless I’m missing something, however, you never increment your retry counter. So if the call fails, it actually does create an infinite loop. You’d have to add the “+1” in the call:

    setTimeout(function(){ fileMakerCall(payload,retry+1); },500);

    • John Sindelar

      Thank you, Max! In all our testing, we never saw it retry more than once, which is probably why we missed this. Much appreciated.

  • Hello Jason,

    Thanks very much for this post, and the code! please note that there is small spelling error on line 25 that breaks the script and throws a console error: “ReferenceError: Can’t find variable: setTimeOut”.

    To fix it, just need to change “setTimeOut(function()” to “setTimeout(function()” in line 25.

    Best regards,

    Andrés

    • seedcode

      Thanks, Andrés! (changed)

    • Jason Young

      Thanks for sharing that Jan, that’s great to know!

  • Thanks for the knowledge Jason! I’ll be using the wrapper in my own stuff.

    • Jason Young

      That’s great to hear Matt, thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

Check out some of our other posts ...

Suggesting Appointment Slots

Show Available Slots that Match Multiple Criteria Schedulers often look for gaps in their schedules to find the open resources for each opportunity. But sometimes,

Introducing Draft Settings Mode

Following up on this idea that people stretch themselves when they feel a little safer, we’ve been very focused on the customization experience for DayBack

New Longer Timescales for DayBack

Resource Scheduling Swimlanes You can now extend the pivoted scheduling view in DayBack to show items by week instead of solely by day. This lets

FileMaker Summer Camp – Recap

Unconference Sessions If you missed Pause in October, here’s a look at the sessions that attendees hosted. All the sessions are listed in this post

COMPANY

FOLLOW ALONG

Stay up to date with the latest news & examples from SeedCode

© 2024 SeedCode, Inc.