All the code we've seen so far was based on the automatic type conversion that happens inside the dart:js
library. This conversion always happens in both directions. Once you know how this happens, you will have a better understanding of the limits of that solution and it will help you avoid mistakes.
Dart supports the following small subset of types by directly converting them from the JavaScript types:
null
, bool
, num
, String
, and DateTime
(basic types)Blob
Event
HtmlCollection
ImageData
KeyRange
Node
NodeList
TypedData
(including its subclasses such as Int32List
, but not ByteBuffer
)Window
Here is set of different types of JavaScript variables that we prepared in the JavaScript file:
var v_null = null; var v_bool = true; var v_num = 1.2; var v_str = "Hello"; var v_date = new Date(); var v_blob = new Blob( ['<a id="a"><b id="b">hey!</b></a>'], {type : 'text/html'}); var v_evt = new Event('click'), var v_nodes = document.createElement("form").children; var v_img_data = document.createElement("canvas"). getContext("2d").createImageData(10, 10); var v_key_range = IDBKeyRange.only(100); var v_node = document.createElement('div'), var v_node_list = document.createElement('div').childNodes; var v_typed = new Int32Array(new ArrayBuffer(8)); var v_global = window;
Now, we'll use reflection to investigate how conversion happens in Dart in the following code:
import 'dart:js' as js; import 'dart:mirrors'; void main() { print(getFromJSContext('v_null')); print(getFromJSContext('v_bool')); print(getFromJSContext('v_num')); print(getFromJSContext('v_str')); print(getFromJSContext('v_date')); print(getFromJSContext('v_blob')); print(getFromJSContext('v_evt')); print(getFromJSContext('v_nodes')); print(getFromJSContext('v_img_data')); print(getFromJSContext('v_key_range')); print(getFromJSContext('v_node')); print(getFromJSContext('v_node_list')); print(getFromJSContext('v_typed')); print(getFromJSContext('v_byte_data')); print(getFromJSContext('v_global')); } getFromJSContext(name) { var obj = js.context[name]; if (obj == null) { return name + ' = null'; } else { return name + ' = ' + obj.toString() + ' is ' + getType(obj); } } getType(obj) { Symbol symbol = reflect(obj).type.qualifiedName; return MirrorSystem.getName(symbol); }
In the preceding code, the getFromJSContext
method returned the name, value, and type of the converted JavaScript object. Here is the result printed on the web browser's console:
v_null = null v_bool = true is dart.core.bool v_num = 1.2 is dart.core._Double v_str = Hello is dart.core._OneByteString v_date = 2014-06-21 18:09:03.145 is dart.core.DateTime v_blob = Instance of 'Blob' is dart.dom.html.Blob v_evt = Instance of 'Event' is dart.dom.html.Event v_nodes = [object HTMLCollection] is dart.js.JsObject v_img_data = Instance of 'ImageData' is dart.dom.html.ImageData v_key_range = Instance of 'KeyRange' is dart.dom.indexed_db.KeyRange v_node = div is dart.dom.html.DivElement v_node_list = [object NodeList] is dart.js.JsObject v_typed = [0, 0] is dart.typed_data._ExternalInt32Array v_byte_data = null v_global = <window> is dart.dom.html.Window
You can check which Dart type will be converted from the JavaScript object with the preceding technique.
All the other JavaScript types are converted to Dart types with the help of a proxy. Let's take a look at the following JavaScript code:
var Engine = function(type) { this.type = type; this.start = function() { alert('Started ' + type + ' engine'), }; }; var v_engine = new Engine('test'),
In the preceding code, we instantiated the Engine
class and assigned it to the v_engine
variable. The following code helps to investigate the conversion of the Engine
class to Dart:
import 'dart:js' as js; import 'dart:mirrors'; void main() { print(getFromJSContext('v_engine')); } getFromJSContext(name) { var obj = js.context[name]; if (obj == null) { return name + ' = null'; } else { return name + ' = ' + obj.toString() + ' is ' + getType(obj); } } getType(obj) { Symbol symbol = reflect(obj).type.qualifiedName; return MirrorSystem.getName(symbol); }
In the preceding code, we copied getFromJSContext
and getType
from the previous code. Here is the result that is displayed in the web browser console:
v_engine = [object Object] is dart.js.JsObject
This result confirms that any ordinary object can be converted to Dart with the JsObject
proxy.
Dart collections can be converted into JavaScript collections with the jsify
constructor of JsObject
. This constructor converts Dart Maps and Iterables into JavaScript objects and arrays recursively, and returns a JsObject
proxy to it. It supports internal collections as well. The following JavaScript code has the variable data
and the toType
and log
methods:
function toType(obj) { return ({}).toString.call(obj). match(/s([a-zA-Z]+)/)[1].toLowerCase() }; var data; function log() { console.log(toType(data)); for (i in data) { console.log('- ' + i.toString() + ': ' + data[i].toString() + ' (' + toType(data[i]) + ')'), } };
Let's take a look at the Dart code that has references to the log
function of JavaScript:
import 'dart:js' as js; void main() { js.JsFunction log = js.context['log']; js.JsArray array = new js.JsObject.jsify([1, 'a', true]); js.context['data'] = array; log.apply([]); js.JsObject map = new js.JsObject.jsify( {'n':1, 't':'a', 'b':true, 'array':array} ); js.context['data'] = map; log.apply([]); }
In the preceding code, we created an array
and assigned it to a JavaScript data
variable. We logged all the items of the JavaScript array
via the apply
method of log. We send empty array as argument of the apply function because the corresponding JavaScript function doesn't have parameters. Later, we created a map
object, filled it, and then call a log
JavaScript function again. To check the support of the internal collections, we inserted the array
into the map
object as the last item. Here is the result:
array - 0: 1 (number) - 1: a (string) - 2: true (boolean) object - n: 1 (number) - t: a (string) - b: true (boolean) - array: 1,a,true (array)
All our objects and internal collections were converted into the correct JavaScript objects.
3.12.76.164