4

Edit: Here is a minimal project that illustrates my issue. You can see the error described by serving it to the browser: pub get and then either pub serve (dartium) or pub build --mode=debug (other browsers).

How can I access an arbitrary JavaScript property from Dart through a JsObjectImpl? I am using the ace.js library with an interop to Dart that I've adapted from a typescript interface, and the method I am calling returns a plain javascript object with key-value pairs.

Dart gives me a JsObjectImpl, which cannot be casted to a Map or a JsObject, both of which have [] accessors. It confusingly seems to inherit from the deprecated JSObject (note the 's' is capitalized in the latter) which does not have the [] accessor, so I can't get the data out.

Some error messages:

  1. When attempting a cast from JsObjectImpl to JsObject:
    ORIGINAL EXCEPTION: type 'JSObjectImpl' is not a subtype of type 'JsObject' of 'obj' where JSObjectImpl is from dart:js JsObject is from dart:js. I get a similar message when using Map as well.

  2. Looking at the object in the debugger, I can frustratingly see the property in JS view but not in the Dart object:
    Chrome debugger showing a property with the key "4"
    The 4: Object is the data I want.

7
  • 1
    can you create a small example which demonstrates this issue? It'll be easier to help if there's something to debug Commented Dec 22, 2016 at 12:23
  • preferred using dartpad.dartlang.org Commented Dec 22, 2016 at 17:01
  • 1
    pub.dartlang.org/packages/js is now a better option than dart:js for dart-js-interop Commented Dec 22, 2016 at 17:02
  • 1
    Just importing another package is not enough. Read the readme of the package pub.dartlang.org/packages/js about how to use it. Commented Dec 22, 2016 at 20:22
  • 1
    I'll help you out - let me just clone your package. Commented Dec 22, 2016 at 20:25

2 Answers 2

10

Ok, this was a fun one, happy holidays :)

It looks like Map is not a supported auto-conversion for package:js. So a couple of things:

  1. Filed https://github.com/dart-lang/sdk/issues/28194
  2. Sent your a PR introducing a workaround

For interested parties, we can use the browser-native Object.keys:

@JS()
library example;

import 'package:js/js.dart';

/// A workaround to converting an object from JS to a Dart Map.
Map jsToMap(jsObject) {
  return new Map.fromIterable(
    _getKeysOfObject(jsObject),
    value: (key) => getProperty(jsObject, key),
  );
}

// Both of these interfaces exist to call `Object.keys` from Dart.
//
// But you don't use them directly. Just see `jsToMap`.
@JS('Object.keys')
external List<String> _getKeysOfObject(jsObject);

And call it once we have an arbitrary JavaScript object:

var properties = jsToMap(toy.getData());
print(properties);
Sign up to request clarification or add additional context in comments.

Comments

0

I had to modify @matanlurey solution so it works on dart 2.12 and is recursive.

import 'dart:js';

/// A workaround to deep-converting an object from JS to a Dart Object.
Object jsToDart(jsObject) {
  if (jsObject is JsArray || jsObject is Iterable) {
    return jsObject.map(jsToDart).toList();
  }
  if (jsObject is JsObject) {
    return Map.fromIterable(
      getObjectKeys(jsObject),
      value: (key) => jsToDart(jsObject[key]),
    );
  }
  return jsObject;
}

List<String> getObjectKeys(JsObject object) => context['Object']
    .callMethod('getOwnPropertyNames', [object])
    .toList()
    .cast<String>();

Comments

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.