Android Question [Solved] How to get HTML/Javascript event values?

fredo

Well-Known Member
Licensed User
Longtime User
In this use case, a webview is used to give a like/dislike rating in a list of images using radiobuttons.
HTML:
<!DOCTYPE html>
<html lang="en">

<head>
    <title>&#43;</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta charset="utf-8" />
    <link rel="stylesheet" type="text/css" href="mystyle.css" />
    <style>
        html,
        body {
            font-family: Verdana, Geneva, sans-serif;
            font-size: 13px;
            width: 98%;
            height: 100%;
        }

        .center {
            display: block;
            margin-left: auto;
            margin-right: auto;
            width: 50%;
        }

        img {
            width: 70%;
            display: block;
            border-radius: 15px;
            margin-left: auto;
            margin-right: auto;
            background-color: white;
            box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
        }

        .bigger {
            font-size: 200%;
            vertical-align: middle;
        }

        a {
            text-decoration: none;
            color: #000;
        }

        /*  https://jsfiddle.net/tc1ef05j/2/   */

        .radioGroup label {
            display: inline-block;
            margin: 0 0 0 1em;
            text-align: center;
            font-size: 2em;
        }

        .radioGroup label input[type="radio"] {
            margin: 0.5em auto;
        }

    </style>

</head>

<body>
    <div class="center">

        <br>
        <br>
        <img src="https://i.imgur.com/L9DV8o3.jpg" alt="image missing">
        <br>
        <div class="radioGroup">
            <label for="markv1">👍<br />
                <input type="radio" name="img1" id="i1v1" value="up" onchange="getRating(this)" />
            </label>
            <label for="markv2">👎<br />
                <input type="radio" name="img1" id="i1v2" value="dn" onchange="getRating(this)" checked="checked" />
            </label>
        </div>

        <hr>
        <br>
        <br>
        <br>
        <img src="https://i.imgur.com/N1opQhr.jpg" alt="image missing">
        <br>
        <div class="radioGroup">
            <label for="markv1">👍<br />
                <input type="radio" name="img2" id="i2v1" value="up" onchange="getRating(this)" checked="checked" />
            </label>
            <label for="markv2">👎<br />
                <input type="radio" name="img2" id="i2v2" value="dn" onchange="getRating(this)" />
            </label>
        </div>



    </div>

    <script>
        function getRating(el) {
            var res = el.id + '-' + el.value
            B4A.Callsub('apwgetrating', res);
        }

    </script>


</body>

</html>

2020-06-19_12-59-47.png


When a radiobutton is changed, an event is triggered, and the result is to be used further in B4A.
B4X:
' Based on: rraswisak's working webext_sample.zip --> https://www.b4x.com/android/forum/threads/webviewextra-call-b4a-sub-from-webview.111151/#content

#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: True
    #IncludeTitle: False
#End Region

Sub Process_Globals
End Sub

Sub Globals
    Private Label2 As Label
    Private Label1 As Label

    Private we As WebViewExtras
    Private WebView1 As WebView
    
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    
    we.addJavascriptInterface(WebView1,"B4A")
    WebView1.LoadUrl(WebViewAssetFile("test1.html"))     ' relevant jsfiddle --> https://jsfiddle.net/bhjdo7Lt/2/

End Sub


public Sub apwgetrating(value As String)  ' <<<<<<<<<<<<<<< result expected here
    Log("#-Sub apwgetRating, value =" & value )
    
    Label1.Text = value
    
End Sub




Sub WebViewAssetFile (FileName As String) As String
   #if B4J
     Return File.GetUri(File.DirAssets, FileName)
   #Else If B4A
    Dim jo As JavaObject
    jo.InitializeStatic("anywheresoftware.b4a.objects.streams.File")
    If jo.GetField("virtualAssetsFolder") = Null Then
        Return "file:///android_asset/" & FileName.ToLowerCase
    Else
        Return "file://" & File.Combine(jo.GetField("virtualAssetsFolder"), _
       jo.RunMethod("getUnpackedVirtualAssetFile", Array As Object(FileName)))
    End If
   #Else If B4i
     Return $"file://${File.Combine(File.DirAssets, FileName)}"$
   #End If
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub


The HTML test code works correctly (relevant jsfiddle --> https://jsfiddle.net/bhjdo7Lt/2/ )

Although our wonderful community has provided countless examples and hints on the topic of "Javascript", it was not possible to get the event-value in B4A.
Warwound has created excellent libs and examples for the webview.

The problem at the moment is the exuberant amount of information that always comes in different combinations / versions of WebviewClient, WebviewExtras, AJWebkit, FlingableWebview.

If you have little background around the mechanisms of the webview, it is very frustrating to find the right variation.
2020-06-19_13-14-54.jpg


Here it would be desirable to have a "single source of truth", like Erel does with the [B4X] hints in older posts ("It is better to use...").

Or a version-true graphical overview of the interaction of the objects involved would also support the ability to think along.

Could someone more competent help me to change the included example project so that the result generated by the script appears in B4A?
 

Attachments

  • WebView_Js_EventValueTest_01.zip
    11.2 KB · Views: 173

Toky Olivier

Active Member
Licensed User
Longtime User
In B4A:
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    
    we.addWebChromeClient(WebView1, "WebView1")
    we.addJavascriptInterface(WebView1,"B4A")
    WebView1.LoadUrl(WebViewAssetFile("test1.html"))     ' relevant jsfiddle --> https://jsfiddle.net/bhjdo7Lt/2/

    
    'WebView1.LoadUrl(WebViewAssetFile("index.html"))
End Sub

In your html page:
JSX:
        function getRating(el) {
            var res = el.id + '-' + el.value
            B4A.CallSub('apwgetrating', true, res);
        }

Note that the correct prototype is CallSub(subName As String, callUIThread As boolean, parameter1 As String)
So: B4A.CallSub not B4A.Callsub (JS is case sensitive) and you need to provide callUIThread parameter. All is said here: https://www.b4x.com/android/forum/threads/webviewextras.12453/#content
Enclosed the sample modified.

PS:
You use the same folder for B4A & B4J Additionnal Libs paths? It's not recommended.
For B4J, I wrapped again WebView component of JavaFX to have same fonctionnalities (execution of JSCode from B4J or getting result from JS to B4J).
 

Attachments

  • WebExtrasSample.zip
    11.2 KB · Views: 223
Upvote 0

fredo

Well-Known Member
Licensed User
Longtime User
That was it!

Many thanks for the constructive advices and the working solution.

This is once again a prime example of the special nature of the B4X community.

Our productivity is not only guaranteed by the excellent product B4X, but also regularly by useful support like in this case from you.
 
Upvote 0
Top