Type conversion

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.

Direct type conversion

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.

Proxy type conversion

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.

Collection conversion

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.76.164