-
Notifications
You must be signed in to change notification settings - Fork 717
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
26a0d2f
commit e08ef7f
Showing
1 changed file
with
174 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,176 @@ | ||
--- | ||
title: Getting started with Javascript interop | ||
description: | ||
--- | ||
description: A basic example of using browswer APIs and a bundled JS libarary. | ||
--- | ||
|
||
In this tutorial, you'll learn the basics of interacting with JavaScript | ||
in Dart, using various JavaScript and browser APIs. | ||
|
||
```dart | ||
import 'dart:js_interop'; | ||
// All top-level JS interop APIs need the @JS annotation. | ||
@JS() | ||
external JSObject get document; | ||
``` | ||
|
||
We use an `@JS`-annotated external top-level getter to access the document that’s | ||
available within `globalThis`. The result is a JS object, and is typed in Dart as a `JSObject`. | ||
An opaque JS object is not very useful, so we define an interop type using | ||
[extension types][] to view it differently: | ||
|
||
```dart | ||
@JS() | ||
external Document get document; | ||
extension type Document._(JSObject _) implements JSObject {} | ||
``` | ||
|
||
We define an interface for the `JSObject`, which allows us to interact with the | ||
`JSObject` by declaring more interop APIs: | ||
|
||
```dart | ||
extension type Document._(JSObject _) implements JSObject { | ||
external JSObject createElement(JSString tag); | ||
} | ||
``` | ||
|
||
We’ve declared an external method within `Document` that allows us to call | ||
instance methods on it, like: | ||
|
||
```dart | ||
var button = document.createElement('button'.toJS); | ||
``` | ||
|
||
An important thing to note is that all values that flow into and out of interop | ||
APIs should be typed as an interop type or an allowed Dart primitive type. | ||
In order to convert some Dart values to a JS value and vice versa, | ||
we use conversion methods like .toJS above. | ||
In the case where a Dart primitive type is used, | ||
the compiler automatically converts the Dart value to a JS value and vice versa, | ||
so we can rewrite the above code as: | ||
|
||
```dart | ||
external JSObject createElement(String tag); | ||
``` | ||
|
||
and call it as: | ||
|
||
```dart | ||
var button = document.createElement('button'); | ||
``` | ||
|
||
The above call creates a button element, | ||
which we can add to the document body using `appendChild`: | ||
|
||
```dart | ||
extension type Document._(JSObject _) implements JSObject { | ||
external JSObject createElement(String tag); | ||
external Body get body; | ||
} | ||
extension type Body._(JSObject _) implements JSObject { | ||
external JSObject appendChild(JSObject child); | ||
} | ||
``` | ||
|
||
```dart | ||
var button = document.createElement('button'); | ||
document.body.appendChild(button); | ||
``` | ||
|
||
It is useful sometimes to register event listeners | ||
so that we know when the button is clicked: | ||
|
||
```dart | ||
extension type ButtonElement(JSObject _) implements JSObject { | ||
external void addEventListener(String event, JSFunction listener); | ||
} | ||
``` | ||
|
||
```dart | ||
var button = ButtonElement(document.createElement('button')); | ||
document.body.appendChild(button); | ||
button.addEventListener('click', (JSObject event) { | ||
print('Clicked!'); | ||
}.toJS); | ||
``` | ||
|
||
Here, we create an interface for a button element and register an event listener | ||
for the “click” event using a Dart function that is converted to a JS function using toJS. | ||
Functions converted using toJS have the same limitations as interop APIs: | ||
their parameter and return types can only be an interop type or a primitive type. | ||
|
||
There are other common types you may come across when using JS interop, | ||
like Promises. We can convert Promises to and from Dart Futures as well: | ||
|
||
```dart | ||
import 'dart:js_interop'; | ||
extension type Response._(JSObject _) implements JSObject { | ||
external bool get ok; | ||
} | ||
@JS() | ||
external Response fetch(String resource); | ||
void main() async { | ||
var response = await fetch('image.png').toDart; | ||
print(response.ok); | ||
} | ||
``` | ||
|
||
The above example uses the fetch API. | ||
|
||
You may also come across Arrays, which also can be converted to and from Dart Lists: | ||
|
||
```dart | ||
import 'dart:js_interop'; | ||
@JS('Array.of') | ||
external JSArray<JSString> arrayOf(String a, String b); | ||
void main() { | ||
var array = arrayOf('hello', 'world'); | ||
var list = array.toDart; | ||
for (var element in list) { | ||
print(element.toDart); | ||
} | ||
} | ||
``` | ||
|
||
The above example uses `Array.of` using renaming to create an Array from two string values, | ||
converts the Array to a List of `JSStrings`, | ||
iterates over the List, and converts and prints out the string values. | ||
|
||
An important thing to note when dealing with generic JS types like `JSArray` | ||
and `JSPromise` is that the generic must be a JS value. | ||
For example, with Lists, you’ll need to convert the contents before converting the List e.g. | ||
|
||
```dart | ||
List<JSString> list = ['hello'.toJS, 'world'.toJS]; | ||
list.toJS; | ||
``` | ||
|
||
or | ||
|
||
```dart | ||
List<String> list = ['hello', 'world']; | ||
list.map((e) => e.toJS).toList().toJS; | ||
``` | ||
|
||
## Learn more | ||
|
||
* For more information on which types have conversions, checkout [Conversions][]. | ||
* For more information on how to write interop APIs, checkout [Usage][]. | ||
* To access common utility functions, checkout: | ||
* The [`dart:js_interop`][] library, and | ||
* The [`dart:js_interop_unsafe`][] library. | ||
* [`package:web`][] exposes many of the browser APIs | ||
(including those used in the above examples) through interop declarations. | ||
|
||
[Conversions]: https://dart.dev/interop/js-interop/js-types#conversions | ||
[Usage]: https://dart.dev/interop/js-interop/usage | ||
[`dart:js_interop`]: https://api.dart.dev/main/dart-js_interop/dart-js_interop-library.html | ||
[`dart:js_interop_unsafe`]: https://api.dart.dev/main/dart-js_interop_unsafe/dart-js_interop_unsafe-library.html | ||
[`package:web`]: /interop/js-interop/package-web |