Evaluate a JavaScript snippet on a WebView and optionally get the result

The WebView offers limited execution of arbitrary JavaScript in the currently loaded web environment. This is done with the <EvaluateJS/> action. Let's look at a simplified example.

<EvaluateJS Handler="{onPageLoaded}">
    var result = {
        url : document.location.href
    };
    return result;
</EvaluateJS>

Note the use of a return statement in the script body. Implementations of JavaScript evaluation APIs generally act like a JavaScript REPL, and when evaluating multiple lines of JS the result of the last statement of the script becomes the returned value. For instance, "1+5" is completely valid JS when evaluated and returns the expected value of "6".

This can result in odd-feeling JS, where referencing an object becomes an implicit return statement, whereas an explicit return is not allowed.

var result = {};
result.foo = "bar";
result; // using return here is invalid JS

To make this feel better and allow return, we currently inject the user's JS in the form of a function:

(function() { USER_JS })();
Reading the result value

When we evaluate the JavaScript we are currently bound by platform restrictions in a key way: String is the only allowed return value type on Android, our lowest common denominator. What this means is that any return value passed from the evaluated script must by necessity be returned as JSON and parsed back from it on the Fuse end. Even if all you want is the result of some arithmetic, you'd still receive it as a string and require a cast. Instead of forcing you to routinely return JSON.stringify(foo) from your own JS we handle this by always wrapping your JS in JSON.stringify before evaluation:

JSON.stringify( (function() { USER_JS })() );

The returned JSON string here is then put into a result object with the json key. This is for clarity, so you never forget that the data you are receiving is a JSON string that you will need to parse.

<JavaScript>
    module.exports = {
        onPageLoaded : function(result)
        {
            var url = JSON.parse(result.json).url;
        }
    };
</JavaScript>

Note that of course return is optional. If you don't return anything from your evaluated JS the return value of the expression will simply be "null".

Example

<Grid Rows="0.15*, 1*">
    <JavaScript>
        var Observable = require('FuseJS/Observable');
        var webViewTitle = Observable("<Unknown>");

        function updateTitle(args) {
            webViewTitle.value = JSON.parse(args.json);
        };

        module.exports = {
            webViewTitle: webViewTitle.map(function(title) { return "HTML Title: " + title; }),
            updateTitle: updateTitle
        }
    </JavaScript>
    <Text Value="{webViewTitle}" Alignment="Center" />
    <NativeViewHost>
        <WebView Url="https://fuseopen.com">
            <PageLoaded>
                <EvaluateJS JavaScript="return window.document.title;" Handler="{updateTitle}" />
            </PageLoaded>
        </WebView>
    </NativeViewHost>
</Grid>

Location

Namespace
Fuse.Triggers.Actions
Package
Fuse.Controls.WebView 2.9.1
Show Uno properties and methods

Interface of EvaluateJS

Inherited from TriggerAction

AtProgress : float ux

A value between 0 and 1 for when the action should be performed. Alternative to Delay.

Delay : float ux

The number of seconds after the start of the trigger that the action should be performed.

TargetNode : Node ux

The node that the action targets. If not specified then the enclsoing Trigger will be used. Several triggers can look for a target starting from this point. Some triggers require a Target to be specified.

Unroot uno

Called when the owner of this object is unrooted. This gives an action to cleanup resources or cancel pending actions.

Inherited from PropertyObject

Inherited from object

Attached UX Attributes

GlobalKey (attached by Resource) : string ux

The ux:Global attribute creates a global resource that is accessible everywhere in UX markup.

Implemented Interfaces