5

I try to use webview evaluateJavascript and got error. WebView Controller has 2 function; evaluateJavascript, and loadUrl. I tested both in onPageFinished: (url){}, so I can initialise my javascript code. Documentation is not clear. But the error tells me something missing pr not implemented in webview plugin. I am trying to load page and initialising some basic javascript so I can hide some part of the page.

How to use Flutter webview evaluateJavascript?

Error:

Syncing files to device iPhone X...
flutter: Page finished loading: https://stackoverflow.com/
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: PlatformException(evaluateJavaScript_failed, Failed evaluating JavaScript, JavaScript string was: 'javascript:(function() { var head = document.getElementsByClassName('top-bar js-top-bar top-bar__network _fixed')[0].style.display='none'; })()'
Error Domain=WKErrorDomain Code=4 "A JavaScript exception occurred" UserInfo={WKJavaScriptExceptionLineNumber=1, WKJavaScriptExceptionMessage=TypeError: undefined is not an object (evaluating 'document.getElementsByClassName('top-bar js-top-bar top-bar__network _fixed')[0].style'), WKJavaScriptExceptionColumnNumber=117, WKJavaScriptExceptionSourceURL=https://stackoverflow.com/, NSLocalizedDescription=A JavaScript exception occurred})
#0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:564:7)
#1      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:302:33)
<asynchronous suspension>
#2      WebViewController.evaluateJavascript (package:web<…>
Application finished.

Code:

    class _WebViewExampleState extends State<WebViewExample> {
    WebViewController _myController;
      bool _loadedPage = false;

      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        setState(() {
          _loadedPage = false;
        });
      }


      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.green,
            title: const Text(
              ’Stackoverflow’,
              style: TextStyle(fontSize: 14),
            ),

          ),
          body: Builder(builder: (BuildContext context) {
            return new Stack(
              children: <Widget>[
                new WebView(
                  initialUrl: 'https://stackoverflow.com',
                  javascriptMode: JavascriptMode.unrestricted,
                  onWebViewCreated: (controller){
                    _myController = controller;
                  },
                  javascriptChannels: <JavascriptChannel>[
                    _toasterJavascriptChannel(context),
                  ].toSet(),
                  onPageFinished: (url){
                    print('Page finished loading: $url');

                    _myController.evaluateJavascript("javascript:(function() { " +
                        "var head = document.getElementsByClassName('top-bar js-top-bar top-bar__network _fixed')[0].style.display='none'; " +
                        "})()");

/*
                _myController.loadUrl("javascript:(function() { " +
                    "var head = document.getElementsByClassName('top-bar js-top-bar top-bar__network _fixed')[0].style.display='none'; " +
                    "})()");
*/

                    setState(() {
                      _loadedPage = true;
                    });
                  },
                ),
                _loadedPage == false
                    ? new Center(
                        child: new CircularProgressIndicator(
                            backgroundColor: Colors.green),
                      )
                    : new Container(),
              ],
            );
          }),

        );
      }

      JavascriptChannel _toasterJavascriptChannel(BuildContext context) {
        return JavascriptChannel(
            name: 'Toaster',
            onMessageReceived: (JavascriptMessage message) {
              Scaffold.of(context).showSnackBar(
                SnackBar(content: Text(message.message)),
              );
            });
      }

    }

4 Answers 4

10

All the answers are outdated now, and evaluateJavascript no longer existed in the package. It's now call runJavascript; If you don't need value return from your javascript, otherwise use runJavascriptReturningResult.

You can see an example here

Sign up to request clarification or add additional context in comments.

Comments

3

You are using it correctly - though you don't need to wrap it inside

javascript:(function() { }

Anyway, this is the important part of the error message:

TypeError: undefined is not an object

This merely means the object for which you're trying to modify the style attribute doesn't exist.

If you try the following code

_myController.evaluateJavascript("console.log(document.documentElement.innerHTML);");
                  setState(() {
              _loadedPage = true;
            });

and take a look at the debug console, you'll notice that this code - which should return the complete HTML for the stackoverflow website - just returns a little bit and not enough to reach the header element which uses the class top-bar js-top-bar top-bar__network _fixed.

4 Comments

I couldn't see anything in debug console. All I see this: Xcode build done. 11,6s Syncing files to device iPhone X... flutter: Page finished loading: stackoverflow.com
And if you try _myController.evaluateJavascript("console.log(document.title);"); setState(() { _loadedPage = true; });
I am using IntelliJ and nothing shows in debug console, all I see same as before. Page finished loading: stackoverflow.com
Its work when I use document.getElementById. But doesn't work with document.getElementsByClassName. Thanks.
2

Using document.getElementsByClassName('someclassname')[0] worked for me.

2 Comments

Did you use it like this ? controller!.evaluateJavascript("document.getElementsByClassName('someclassname')[0];")
Thanks, this is a working, but there is a gotcha, inside onLoadStop, you may need to do Future.delayed(const Duration(seconds: 5), () { controller.evaluateJavascript(source: '''document.getElementById('download-pdf-all').click()'''); });
2

Use controller.evaluateJavascript to edit on webview javascript, available in in_app_webview packages.

Notes that controller.evaluateJavascript need to write inside onLoadStop() functions. Inside the code where your WebView is finished loaded.

Example:

String Username = 'User';
String Password = '123';
InAppWebView(
 ...
onLoadStop: (controller, url) async{
            pullToRefreshController.endRefreshing();
            controller.evaluateJavascript(
                source: '''
                document.getElementById('uname').value = "$Username"; //Autofill in username field
                document.getElementById('pwd').value = "$Password"; //Autofill in password field
                var z = document.getElementById('submitBtn').click(); //Autoclick function
                '''
            );

            setState(() {
              this.url = url.toString();
              urlController.text = this.url;
            });

          },
 ...
)//InAppWebView

3 Comments

document.getElementById not working
Make sure that your element id is correct. You can open the browser developer tool to check the element id. Also, remember to double-check the format: controller.evaluateJavascript( source:''' Your content ''' );
The page wasn't fully loaded and available in onLoadStop so I have to add a wait of 5 seconds and after that it's working fine now. Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.