Webview intergration Part 1

This blog entry is the first part of a small series that deals with the basics of integrating web views in FileMaker.

Here, we will focus on the fundamental aspects of HTML and jQuery/JavaScript that are relevant to us. For additional information, there are numerous websites out there that can help you further. I didn’t want to create another HTML course 🙂

Moreover, I am by no means an HTML/CSS/jQuery/JavaScript ninja; instead, I’ve only acquired the parts necessary for problem-solving. Therefore, my approaches are probably not the formally correct methods, but they serve their purpose for me.

More importantly, the interaction between FileMaker and HTML/jQuery is what matters. Simple tips in this regard can save a lot of effort and time.

First, let’s address the question of why one should use web views in FileMaker – what are the advantages and disadvantages of such solutions?

Let’s dive right in with the “why.”

Claris continuously updates FileMaker, but in some areas, it feels like being stuck in the 1980s. GUI elements, in particular, seem to have remained somewhere before the era of web browsers.

One obvious example is FileMaker portals. Portals in FileMaker can’t be sorted natively by different columns, nor can you adjust column width in Browse mode, or even adjust row height for multiline text.

There are many instances where HTML allows us to easily customize properties of objects that are not editable in FileMaker. I’ve heard from colleagues that they calculate complex formulas in web views for better performance.

Since I started working with web views, I find myself wondering if many problems could be solved more easily with HTML/jQuery/JavaScript. This is where a huge advantage of web views combined with JavaScript/jQuery comes into play: there are countless (free) plugins on the internet for almost every problem, and once you know how to integrate these plugins, you have access to fantastic tools.

Before I continue praising the advantages endlessly, let’s not forget about the drawbacks. One disadvantage I always mention is the compatibility with newer versions of FileMaker. If FileMaker functionality or web viewer compatibility changes, you might face issues.

Some functions of plugins from the internet also behave differently on Windows and Mac. I once had a problem when Edge was declared the default browser on Windows machines, and my HTML links suddenly prompted for permission with every click.

And a significant drawback is that even the best and most beautiful plugin sometimes refuses to cooperate with FileMaker – at least, I haven’t managed to make it work.

Now, as we delve into using web views, let’s keep in mind what is needed and how we can easily incorporate it into FileMaker.

Firstly, in the FileMaker database, under File/Manage/Security, in each account, the checkbox for “Allow URLs to perform FileMaker scripts” should be checked so that a web view can execute an FM script with a URL call. Although this is considered an outdated method of executing a script from a web view, we’ll revisit why it can be essential in a later part of this series. The current way (from FM version 19 onwards) to call an FM script from a web view is the command “FileMaker.PerformScriptWithOption ( script, parameter, option );” or without the option of how currently running FM scripts should behave: “FileMaker.PerformScript ( script, parameter );”. To use this command in the web view, you need to enable it in the web view settings by checking “Allow JavaScript to perform FileMaker scripts.” And while we’re here, let’s also check “Allow interaction with web viewer content” so that we can click a button in the web view HTML. All other checkboxes can be unchecked.

A simple HTML page has the following structure:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>...</style>
...
<script type="text/javascript">...</script>
...
<script>
...
</script>
</head>
<body>
...
</body>
</html>

I’ll briefly explain the sections and how I proceed to include HTML content. I strongly recommend visiting https://www.w3schools.com and going through some “Try” examples to understand these concepts better!

In the `<head>` section, you’ll find the `<style>` tag where CSS (Cascading Style Sheets) is defined. CSS can be thought of as a list in which elements are assigned styles that deviate from default values, such as different fonts, borders, or spacing between elements – essentially anything related to presentation. You can include as many style sheets as needed.

A style sheet is essentially text in the form:

Element { Property: Value; }

For example:

body {
background-color: #F0F0F0;
padding: 0px;
}

Here, we give the body element a gray background color and an inner padding of 0 pixels.

The `<script>` part contains the script executed in the web view – for example, JavaScript. These scripts can even be externally linked via the internet using a web address. You can include as many `<script>` tags as needed.

To use jQuery functionality in the web view, you can simply include the jQuery library like this:

<script src="https://code.jquery.com/jquery-3.6.0.js"></script>

This loads jQuery from the internet. However, we’ll discuss how to store it in FileMaker later.

The `<body>` tag contains the actual content to be displayed – text, buttons, tables, or anything else needed for your application. Again, I strongly recommend checking the https://www.w3schools.com site to explore the vast selection of elements and their properties.

After learning what is needed, let’s discuss how to provide it. I personally prefer using placeholders in the HTML document, which are then replaced by content or values. The advantage is that it keeps the HTML code

concise, and parts that don’t change can be externalized.

For the HTML head, it looks like this:

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>__jquery-ui.css</style>
<script type="text/javascript">__jquery-1.10.2.js</script>
<script type="text/javascript">__jquery-ui.js</script>
<style>__style.css</style>
<script>
...
</script>
</head>
<body>
...
</body>
</html>

To include the files, you can download the libraries from the internet and store them in a parameter table in text fields. I connect this parameter table via an X-relationship with the main table where our web view is generated.

By the way, I connect all primary occurrences of tables in my solutions via an X-relationship with the parameter table. This way, I can not only access parameters from any table but also access all primary occurrences through the parameter table, which can be useful, e.g., when accessing a global field from another table.

For passing values to the web viewer, I also use simple placeholders that are replaced in the web viewer.

If the libraries are stored in the parameter table in text fields and retrieved into the web view via an X-relationship, you can place the following calculation directly in the web view:

"data:text/html," & Substitute ( Parameter::HTML ;
["__jquery-1.10.2.js" ; Parameter::jquery_1.10.2.js] ;
["__jquery-ui.js" ; Parameter::jquery_ui.js] ;
["__jquery-ui.css" ; Parameter::jquery_ui_css] ;
["__style.css" ; Parameter::style.css] ;
["__script" ; Parameter::Script] ; // Only needed if using FM version < 19
["__value" ; Main::ReturnValue]
)

Here, before the `Substitute` command, the text “data:text/html,” tells the web viewer that it should interpret the following text as an HTML page rather than loading a page from a URL.

The field that contains the actual HTML code is aptly named ‘HTML.’ It also resides in the parameter table since it only needs to contain the code once and acquires the values of the current ‘Main’ dataset through substitution.

This always has the advantage that one can display the field and make changes directly in the code, which become immediately visible in the web view.

Looking at the `Substitute` itself, I replace 4 fields from the Parameter table:
– `Parameter::jquery_1.10.2.js`: This is the actual jQuery extension of JavaScript with many useful shortcuts that make accessing and handling HTML elements super easy. We’ll delve into this later.
– `Parameter::jquery_ui.js`: Provides UI components/interactions/effects/widgets/themes within jQuery. You don’t always need these extensions, but I usually import them together. This file is a pre-made style sheet file from https://jqueryui.com and is highly recommended. Our example today is a “Slider” from the Widget list in this file.
– `Parameter::style.css`: This is the stylesheet document that we use to customize the appearance of our HTML elements.
– `Parameter::Script`: This is a calculation that creates the call to the script for an FM version < 19. This call still works, and there are use cases in FM 19 and later where you need this type of script call, but I’ll cover that in the last part of this series. The formula itself adds a version number to the link (from FM version 19):

Let ( 
[
sc_appVersion = Floor ( GetAsNumber ( Substitute ( Get ( ApplicationVersion ) ; "." ; "," ) ) ) ;
sc_fmpProtocol = Case ( sc_appVersion ≥ 18 ; "fmp" & sc_appVersion & "://" ; "fmp://" )
] ;

sc_fmpProtocol & "$/" & Get ( FileName ) & "?script=ReturnSlider"

)

– `Main::ReturnValue`: Our return value to the web view and the only field in the ‚Main’ table – in this case, a simple field value that will be replaced in HTML.

You can also use the FileMaker command `Perform JavaScript in Web Viewer` to call a JavaScript function and pass parameters. But I’ll cover that later.

Okay, we’ve discussed the basics of passing values to and from the web view, and we can finally focus on the content.

For simplicity in this first part, I’ve chosen the “Slider with Maximum” demo from https://jqueryui.com/slider/#rangemin. It provides exactly what we’ve worked on so far and is a practical application of a function that FileMaker simply doesn’t have.

The demo code from the site looks like this:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery UI Slider - Range with fixed maximum</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<script>
$( function() {
$( "#slider-range-max" ).slider({
range: "max",
min: 1,
max: 10,
value: 2,
slide: function( event, ui ) {
$( "#amount" ).val( ui.value );
}
});
$( "#amount" ).val( $( "#slider-range-max" ).slider( "value" ) );
} );
</script>
</head>
<body>
<p>
<label for="amount">Minimum number of bedrooms:</label>
<input type="text" id="amount" readonly style="border:0; color:#f6931f; font-weight:bold;">
</p>
<div id="slider-range-max"></div>
</body>
</html>

Now, if we insert our placeholders, the code looks like this:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>__style.css</style>
<script type="text/javascript">__jquery-1.10.2.js</script>
<script type="text/javascript">__jquery-ui.js</script>
<script>
$( function() {
$( "#slider-range-max" ).slider({
range: "max",
min: 1,
max: 10,
value: __value,
slide: function( event, ui ) {
$( "#amount" ).val( ui.value );
}
});
$( "#amount" ).val( $( "#slider-range-max" ).slider( "value" ) );
} );
</script>
</head>
<body>
<p>
<label for="amount">Minimum number of bedrooms:</label>
<input type="text" id="amount" readonly style="border:0; color:#f6931f; font-weight:bold;">
</p>
<div id="slider-range-max"></div>
</body>
</html>

I removed the `<title>` tag and the theme’s CSS for simplicity and used our own “style.css.” Our “style.css” consists only of a single selector “body”:

body {
font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif";
font-size: 62.5%;
}

Here, we give the “body” a font and a font size. That’s all.

In the demo code, you can already see the significant advantage of jQuery. There is a tag `$( function() {});`, which is a shorthand for the JavaScript code `$(document).ready(function() { … });`, ensuring that the following code is executed only when the entire content (the so-called DOM) is fully loaded.

Furthermore, in the pre-defined function, you can see how easy it is in jQuery to directly address an object: `$( “#slider-range-max” ).slider({});` addresses the slider element with the “ID” “slider-range-max” and gives it functionality and default values. Similarly, you can easily address a body element within the DOM with `”#amount”`.

To achieve this in pure JavaScript, you would need to loop through all DOM objects and search for the ID “slider-range-max” or “#amount”. jQuery simplifies this background work, very clever!

For those who want more details, you can check here: https://api.jquery.com/id-selector/

The two mentioned elements can be found further down in the “body”:

<body>
<p>
<label for="amount">Minimum number of bedrooms:</label>
<input type="text" id="amount" readonly style="border:0; color:#f6931f; font-weight:bold;">
</p>
<div id="slider-range-max"></div>
</body>

So, you can easily imagine that the logic for the display objects of the `<body>` is contained in the `<script>` part.

Now comes the truly exciting part of our connection between Webview and FileMaker. We need to find a hook that calls a script when the slider value is changed so that we can write the current value into a FileMaker field. And that is the tricky part because, as mentioned earlier, not every plugin makes it easy to find or create such a hook. I have sometimes spent days trying to get a plugin to make such a call to FileMaker, and sometimes it simply does not succeed.

In most cases, the documentation of the corresponding plugin helps us. For our slider, under https://api.jqueryui.com/slider/, among the events triggered by the slider, we find “change,” and that is exactly what we are looking for: https://api.jqueryui.com/slider/#event-change

So, we now extend the slider function with this event and build the hook for our FileMaker script call:

$( "#slider-range-max" ).slider({
range: "max",
min: 1,
max: 100,
value: __value,
slide: function( event, ui ) {
$( "#amount" ).val( ui.value );
},

change: function(event, ui) {
event.preventDefault();
var str = $("#slider-range-max").slider( "value" );
FileMaker.PerformScript ( 'ReturnSlider', str );
}
});

The line `event.preventDefault();` prevents the event from having a default behavior because we want to specify the behavior.

Then we retrieve the current value of the slider into a variable. In the documentation, we see that in the “change” event under “ui,” there is an entry:

value
Type: Number
The current value of the slider.

That is exactly what we are looking for. So, we tell the element with the ID “slider-range-max” via jQuery: give us your content with `.slider( “value” )`: `var str = $(“#slider-range-max”).slider( “value” );`

This may sound more complicated than it is, and when you carefully look at such documentation, you will find such callbacks or event listeners well documented in almost all plugins.

The hardest part is now done. Now, we just need to call a script in FileMaker and pass the value:

Since FM 19, FileMaker provides a specific JavaScript command for this: `FileMaker.PerformScript ( script, parameter );`

In our case, we call the script “ReturnSlider” with the parameter “str” in our file: `FileMaker.PerformScript ( ‘ReturnSlider’, str );`

If it’s not an FM 19 version but an older version of FileMaker, you can also call a FileMaker script and pass a parameter via the URL protocol (a link) using the following two commands:

var FMPURL = "__script&param="+str ;
window.location = FMPURL;

That’s why, at the beginning of the file, under Settings/Security, we set the checkbox for “URLs may perform FileMaker scripts.”

Our FileMaker script then looks very simple:

Set Field [ Main::ReturnValue ; Get ( ScriptParameter ) ] 

This script simply sets the current slider value into the “ReturnValue” field in the “Main” table of our file.

Okay, and why do we need the placeholder `__value`? We also want to set the slider value via script and use a similarly simple script “Set slider value” that only checks for a value between 1 and 10 and then writes it into the “ReturnValue” field in the “Main” table:

Show Custom Dialog [ "Note" ; "Please enter a slider value between 1 and 10" ; $value ] 
If [ GetAsNumber ( $value ) < 1 OR GetAsNumber ( $value ) > 10 ]
Show Custom Dialog [ "Note" ; "Error: the value entered is outside the valid range" ]
Exit Script [ Text Result: ]
End If
Set Field [ Main::ReturnValue ; $value ]

Because the Webview acts like a calculation field, the value in the placeholder is replaced, and thus, the slider in the Webview is changed.

If your head is spinning now, it’s no wonder; that was a lot of information all at once. But in the first part, I wanted to have a working example as a result – only a lot of basic knowledge is needed for that. I had to work on all this over a longer period and can only recommend trying it yourself – it’s really worth the effort.

Once you have internalized these basics, the next plugins are very easy to integrate because the routines are almost always the same.

I hope this provides you with an entry into the topic, and as always, feel free to send me an email if you have any questions!

If you like to have an open version of the file, just send me an email.