Interacting with JavaScript

There is a two-way communication channel between a WebView and the navigator.cascades object in the JavaScript environment. This channel allows JavaScript to initiate actions that your app must execute. This channel also allows your app to communicate the status of the operation. For example, you can use JavaScript to add input from text fields in your app into a form that is submitted on a webpage.

Here's an overview of the classes that you need:

Architectural diagram showing the JavaScript classes.

The JavaScriptWorld class is an important utility class that you can use to specify the execution environment for your JavaScript.

You must use JavaScriptWorld::Normal if you want to call a JavaScript function defined on a webpage that is displayed in a WebView in your app. JavaScript that is run in Normal mode is run in the same environment as all other JavaScript code for the WebView.  

You can use JavaScriptWorld::Isolated if you want to avoid your JavaScript interacting accidentally with other JavaScript that is defined on the webpage. JavaScript that is run in Isolated mode is run in a separate, isolated environment. If you use JavaScriptWorld::Isolated, JavaScript defined in your app cannot interact with any JavaScript code or data that the webpage defines or loads.

The code sample below displays a text input field and a WebView that shows the history of what you entered in the text input field. The navigator is used to retrieve your text input and add it to the history.

You can use JavaScript to change the appearance of a webpage or navigate to another webpage. You can also turn off the ability to execute JavaScript from a webpage that you displayed in a WebView in your app by setting the javaScriptEnabled property of the WebSettings to false.

In the code sample, an HTML file is created that contains the JavaScript necessary to interact with the WebView. The HTML file is placed in the assets folder of the project.

Screen showing a simple JavaScript sample in a WebView.
<script type="text/javascript">
navigator.cascades.onmessage = function onmessage(message) {
    document.body.innerHTML += "<p>You replied: " + message + "</p>";
    navigator.cascades.postMessage("Anything else?");
    document.body.innerHTML += "<p>Then I said: Anything else?</p>";

// Try sending a first message
navigator.cascades.postMessage("Hello, Cascades!");
<p>I said: Hello, Cascades!</p>

Now you can set up your UI with a WebView to present your HTML containing the JavaScript to be executed on the webpage, a TextField for the user to type a reply, and a Button for the user to click to send the reply.

You'll notice in the code sample below that the settings.viewport property has been set to {"width" : "device-width", "initial-scale" : 1.0 } to make the text on the webpage readable. This setting scales the webpage to 160 dpi, which makes the default web font size of 16 pixels more readable. For more information about scaling on a webpage, see viewport.

Page {
    Container {
        id: container 
        background: Color.LightGray
        layout: StackLayout { orientation: LayoutOrientation.TopToBottom }

        Container {
            id: messageReceived
            layout: StackLayout { orientation: LayoutOrientation.TopToBottom }
            minHeight: 60

            Label {
                id: messageLabel
                objectName: "messageLabel"
                text: " (no message received)"
            } // container with a label showing the message that was posted

        Container {
            id: reply
            layout: StackLayout { orientation: LayoutOrientation.LeftToRight }
            minHeight: 60
            TextField {
                id: replyField
                layoutProperties: StackLayoutProperties { spaceQuota: 1.0 }
                objectName: "replyField"
                text: "(type your reply here)"

            Button { 
                id: replyButton
                text: "Reply"
                onClicked: {
                    preferredWidth: 100
            } // container with a text field and a reply button

            ProgressIndicator {
                id: progressIndicator
                topMargin: 10
                leftMargin: 10
                bottomMargin: 10
                fromValue: 0
                toValue: 100
                preferredWidth: 800
            } // progress of the webview loading

            ScrollView {
                scrollViewProperties {
                    scrollMode: ScrollMode.Both
                layoutProperties: StackLayoutProperties { spaceQuota: 1.0 }
                Container {
                    background: Color.LightGray
                    layout: StackLayout { 
                        orientation: LayoutOrientation.TopToBottom }

                WebView {
                    id: webView
                    url: "local:///assets/test.html"
                    settings.viewport: {"width" : "device-width", 
                                        "initial-scale" : 1.0 } 
                    onLoadProgressChanged: {
                        progressIndicator.value = loadProgress

                    onMessageReceived: {
                } // webview

                Label {
                    id: bottomLabel
                    text: "Bottom of WebView"
                } // container within scrollview
            } // scrollview
        } // main container
    } // page

You may need to wait until the webpage has loaded before calling evaluateJavaScript(). You can't assume that the page contents will be loaded immediately after the creationCompleted() signal is emitted. If the JavaScript depends on the page contents, you need to listen for the loadingchanged() signal to determine if the webpage has finished loading.

Last modified: 2013-12-21

comments powered by Disqus