How to pass options to javascript function using dart:js?

Issue

I have the following functional javascript code to demonstrate what I want to achieve. It should output the object passed to the method, and then the value of the property "a".

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <script>
    window.theObjectCall = function(x) {
      console.log(x);
      console.log(x.a);
    }
  </script>
  <script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

I have the following dart code, and it works, but "a" is not accessible as I expect.

@JS('window')
library whatever;

import 'dart:js';

import 'package:js/js.dart';

@JS('theObjectCall') // Accessing method getCurrentPosition from Geolocation API
external void theJsObjectCall(JsObject theObject);

void someJsCallWithObject() {
  var object = JsObject(context['Object']);
  object['a'] = 'xxx';
  theJsObjectCall(object);
}

Executing the below logs "undefined" in the console.

enter image description here

Solution

You should define your objects separately as shown in sample below. The reason is javascript is opaque to dart classes including JSObject. As the documentation suggests its just a proxy for you to access a js ojects properties in Dart. I am not sure if you can use it.

However if you already know the structure of the object you want to pass then you can define an anomymous class with that structure and pass it the defined JS function. Then dart2js will take care of the conversion appropriately.

@JS('window')
library whatever;

import 'dart:js';

import 'package:js/js.dart';
import 'package:flutter/material.dart';

@JS('theObjectCall') // Accessing method getCurrentPosition from Geolocation API
external void theJsObjectCall(ObjectYouWantToSend theObject);

void someJsCallWithObject() {
  ObjectYouWantToSend oywts = ObjectYouWantToSend(a: 'xyz');
  theJsObjectCall(oywts);
}

@JS()
@anonymous
class ObjectYouWantToSend {
  external factory ObjectYouWantToSend({
    String a,
  });
  external String get a;
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Container(
          child: Center(
            child: FlatButton(
              onPressed: someJsCallWithObject,
              child: Text('Call The js Function.'),
            ),
          ),
        ),
      ),
    );
  }
}

You can find the code here in my repo.

This is how it looks when deployed.
enter image description here

Answered By – Abhilash Chandran

Answer Checked By – Dawn Plyler (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *