Using Dart in JavaScript and JavaScript in Dart is very easy, although there are some limitations right now that will hopefully be resolved in the future. Basically, when exchanging data between JavaScript and Dart, all you have to do is to wrap/unwrap Dart objects with JsArray
, JsFunction
, or JsObject
proxy classes from the dart:js
built-in package.
Some built-in types don't need any proxy wrapper. The most common are null
, bool
, num
, String
, DateTime
, HtmlCollection
, Event
, Node
, and NodeList
.
Let's say we're writing a JavaScript app where we want to reuse our existing FuzzySearch
class and print all results to the console.
As of now, we can't just expose the class definition and then create instances of it in JavaScript. We can't even create an instance of FuzzySearch
and expose the entire object to JavaScript, where you could call FuzzySearch.search()
or set FuzzySearch.list
by yourself.
We need to wrap all calls to Dart into exposed JavaScript functions.
Create three files in the web
directory: test_fuzzy.dart
, test_fuzzy.js
, and test_fuzzy.html
. We'll start with test_fuzzy.html
(again, we're omitting the unnecessary code):
<!-- web/test_fuzzy.html --> <body> <script type="application/dart" src="test_fuzzy.dart"></script> <script data-pub-inline src="packages/browser/dart.js"></script> <script src="test_fuzzy.js"></script> </body>
We still need some Dart code in the main()
function that exposes what we want even when there's no app logic in it. Then add the following in test_fuzzy.dart
:
// web/test_fuzzy.dart import 'dart:js'; import 'package:Chapter_02_doc_search/fuzzy.dart'; void main() { FuzzySearch fuzzy = new FuzzySearch(); context['dart_fuzzy_set_list'] = (JsArray array) { fuzzy.list = array.toList(); }; context['dart_fuzzy_search'] = fuzzy.search; }
The top-level context
variable comes from the dart:js
package. You can think of it as the window
object in JavaScript. We create two functions:
dart_fuzzy_set_list()
: This takes a JavaScript array as an argument, creates a List
object from it, and passes it to our instance of FuzzySearch
dart_fuzzy_search()
: This just exposes FuzzySearch.search()
for this instanceThen, in test_fuzzy.js
, we use vanilla JavaScript:
// web/test_fuzzy.js window.onload = function() { var terms = ['strpos', 'str_replace', 'strrev', 'substr', 'strtotime']; window.dart_fuzzy_set_list(terms); var results = window.dart_fuzzy_search('srr'), console.log(results); for (var i = 0; i < results.o.length; i++) { console.log(results.o[i]); } };
That's it. When we run Pub Build (which compiles our Dart code to JavaScript) and open test_fuzzy.html
in a browser, it does exactly what we expect:
In the end, it's not that bad even with these limitations and it's already usable.
There's a new https://github.com/dart-lang/js-interop package for Dart-JS interoperation in development right now, which should solve the current limitations of dart:js
.
In practice, you'll probably need to use a lot of existing code already written in JavaScript from Dart. In this app, we might want to use jQuery's fadeIn()
and fadeOut()
functions to show/hide autocomplete.
There're two key methods, JsFunction.apply()
and JsObject.callMethod()
, that we'll use and that have the same purpose as in vanilla JavaScript.
We'll add the jQuery package to the project's dependencies in pubspec.yaml
(Dart packages don't need to contain any Dart code). This package contains only the jquery.js
file that we add to index.html
:
<script src="packages/jquery/jquery.js"></script>
Now, in DocSearch
class, add a new JsFunction _jQuery
property and initialize it with a proxy object for jQuery in the constructor:
_jQuery = context['jQuery'];
Finally, update methods to show/hide autocomplete:
void showAutocomplete() { (_jQuery.apply([_ul]) as JsObject).callMethod('fadeIn', [500]); } void hideAutocomplete() { (_jQuery.apply([_ul]) as JsObject).callMethod('fadeOut'), }
We're basically calling $(ulElement).fadeIn(500)
and $(ulElement).fadeOut()
. The as
keyword means type casting. We're using it here because we know that calling jQuery selector returns a jQuery object and this object has a fadeIn()
/fadeOut()
JavaScript method.
Note that the parameters that we used don't need any proxy classes. In situations where we need to pass JavaScript objects as arguments, we have to wrap them with JsObject.jsify()
, which accepts any Dart collection.
In Chapter 3, The Power of HTML5 with Dart and Chapter 4, Developing a Mobile App with Dart, we'll use dart:js
again with a more complicated examples.
18.227.79.241