web
web copied to clipboard
Package:web usage for migration
I'm doing a migration to 'package:web' and 'dart:js_interop'. I'm currently using the context object from the 'dart:js' package to store functions in the window object reference. However, I've noticed that there's no direct way to access the context from the 'package:web'.
I need help with this migration. Below is the code snippet I need to migrate
void _connectJsToFlutter({VoidCallback? then}) {
js.context['$jsToDartConnectorFN$iframeViewType'] = (js.JsObject window) {
jsWindowObject = window;
for (final cb in widget.dartCallBacks) {
jsWindowObject[cb.name] = cb.callBack;
}
jsWindowObject[webOnClickInsideIframeCallback] = (onClickCallbackObject) {
_handleOnIframeClick(onClickCallbackObject as String);
};
webViewXController.connector = jsWindowObject;
then?.call();
};
}
Can you provide the correct usage of context and JsObject needed for the migration?
globalContext
is the dart:js_interop
equivalent with JSObject
being the equivalent to JsObject
. Also note that we use static interfaces instead of class wrappers now with dart:js_interop
.
A simple migration might look like the following:
import 'dart:js_interop';
import 'dart:js_interop_unsafe'; // to dynamically set properties using []=
...
void _connectJsToFlutter({VoidCallback? then}) {
globalContext['$jsToDartConnectorFN$iframeViewType'] = (JSObject window) {
JSObject jsWindowObject = window;
for (final cb in widget.dartCallBacks) {
jsWindowObject[cb.name] = cb.callBack.toJS;
}
jsWindowObject.setProperty(webOnClickInsideIframeCallback.toJS, (String onClickCallbackObject) {
_handleOnIframeClick(onClickCallbackObject);
}.toJS);
webViewXController.connector = jsWindowObject;
then?.call();
};
}
It's a little difficult to tell what the types of some of these objects are, but a few key points here are:
- you need to use either a primitive type or an interop type when making a call to JS
- functions are passed using
.toJS
, which will return a newJSFunction
that will call the original function. These functions can also only take in/return primitive types and interop types
For more information, look at https://dart.dev/interop/js-interop/usage and https://dart.dev/interop/js-interop/js-types
Thank you. Understood the usage now.
Also could you let me know if I am doing the right way of doing onbeforeunload.
window.onbeforeunload = () async{
//my code snippet
}.toJS;
Or can I use a event listener to perform the same.
window.addEventListener('beforeunload', (JSAny data) {
//my code snippet
}.toJS);
Yup, both should work (although that first one should take in the event as a parameter and I'm also not sure the async
is necessary). You can also use EventStreamProvider
in lib/src/helpers/events/streams.dart
if you'd rather work with Stream
s: EventStreamProvider<BeforeUnloadEvent>('beforeunload').forTarget(window)
.
Also I am doing callMethod from JsObject and passing List<dynamic> params
as the second parameter.
JsObject if from 'dart:js' package
For migration I am using JSObject from dart:js_interop_unsafe
and doing a callMethodVarArgs
call and passing the List
Also, am I using the correct method from JSObject?
It's better practice to define an interface for the JSObject
using an extension type than use dart:js_interop_unsafe
(see https://dart.dev/interop/js-interop/usage#interop-type-members on how to write an interop extension type), but if you don't statically know the method name, then dart:js_interop_unsafe
and callMethodVarArgs
is ok as the replacement.
How can I pass the List as [List<JSAny?>? arguments]?
What does the List
contain? You'll need to convert the contents of the List
to JSAny
s. If it's a List<String>
for example, you can do a list.map((e) => e.toDart).toList()
to get a List<JSString>
. Or if you have a literal e.g. ['hello', 'world']
, you can just do ['hello'.toJS, 'world'.toJS]
instead.
List contains dynamic type values. It contains string, boolean, number and Set/List.
Assuming the nested Set
s/List
s all contain types that can be converted as well (primitives or other nested structures), one thing you could try is using jsify
which will convert all the entries in that list recursively.
List<dynamic> list = ...;
List<JSAny?> jsList = list.map((e) => jsify(e)).toList();
Where can I get more information or examples of JS interop usage other than https://dart.dev/interop/js-interop/usage?
Besides the js-interop
page and its subsections, I'd look at some examples of existing migrations like those in https://github.com/flutter/packages (just grep for dart:js_interop
) or https://github.com/flutter/devtools. We have some tests in the Dart SDK as well that might be useful: https://github.com/dart-lang/sdk/tree/main/tests/lib/js/static_interop_test.
Of course, if you feel like you still have some questions, feel free to ask. If you want to provide feedback on what documentation might be useful for you or others, you can do so in https://github.com/dart-lang/site-www. There's some ongoing work there to get a "getting started" tutorial.