Combining Dart and JavaScript

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.

Note

Maybe you've already seen somebody using a package:js/js.dart package. This is the old Dart-JS interoperation package, which is deprecated in favor of dart:js.

Using Dart in JavaScript

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 instance

Then, 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:

Using Dart in JavaScript

In the end, it's not that bad even with these limitations and it's already usable.

Note

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.

Using JavaScript in Dart

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.

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

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