I'm a bit of a newb to dart, and trying to get my feet wet by writing some library functions in it.
While I've had no problem calling javascript functions from dart, I'd love to be able to call dart functions from javascript, but so far, I'm not having much like.
For example, I'd love to be able to expose some basic functions from dart, for example like so:
main() {
String foo() {
return "bar!";
}
js.scoped(() {
js.context.foo = foo;
});
}
and then be able to call them from javascript, like so:
<script>
window.onload = function() {
alert("foo() = " + foo());
}
</script>
Is something like this even possible?
No problem ! see Calling Dart from JavaScript.
In your case :
import 'dart:js' as js;
main() {
String foo() {
return "bar!";
}
js.context['foo'] = foo;
}
In Dart 1.20 I had to add allowInterop()
import 'dart:js' as js;
main() {
String foo() {
return "bar!";
}
js.context['foo'] = allowInterop(foo);
}
In Dart 2.3.0 I had to tweak the solution just a bit for allowInterop to play nice.
import 'dart:js' as js;
main() {
String foo() {
return "bar!";
}
js.context['foo'] = js.allowInterop(foo);
}
Related
I'm playing around with a Dart app trying to get fullscreen mode to work. My HTML (excluding boilerplate):
<div id="fullscreen_div">
Clicking this should cause it to go fullscreen!
</div>
My Dart code:
import 'dart:html';
void main() {
var div = querySelector('#fullscreen_div');
div.onClick.listen((MouseEvent e) {
div.requestFullscreen();
print('requested fullscreen');
});
}
Here it is on DartPad.
If I've done this correctly, clicking the div once should cause the div to go into fullscreen mode. On Chromium, this works. When compiled to JavaScript (both debug and minified), this does not happen, and the console outputs:
Uncaught TypeError: undefined is not a function
This happens on both Chrome, Firefox and IE (tested on Windows 7). From what I've understood this is a common JavaScript error, and searching does not bring up anything obvious.
Any ideas why requestFullScreen won't work when dart is compiled to JS?
As pointed out in the comments (thanks Günter!), this is a known issue. #12 in that thread posted a good workaround, edited by me to be a bit more generic:
import 'dart:js';
void fullscreenWorkaround(Element element) {
var elem = new JsObject.fromBrowserObject(element);
if (elem.hasProperty("requestFullscreen")) {
elem.callMethod("requestFullscreen");
}
else {
List<String> vendors = ['moz', 'webkit', 'ms', 'o'];
for (String vendor in vendors) {
String vendorFullscreen = "${vendor}RequestFullscreen";
if (vendor == 'moz') {
vendorFullscreen = "${vendor}RequestFullScreen";
}
if (elem.hasProperty(vendorFullscreen)) {
elem.callMethod(vendorFullscreen);
return;
}
}
}
}
I used this in my code, and replaced this call
div.requestFullscreen();
with
fullscreenWorkaround(div);
which worked great. Tested and working compiled on Chrome and IE.
Here is an extended version of Tobbe hack to use the whole fullscreen API.
import 'dart:html';
import 'dart:js';
// Workaround for https://code.google.com/p/dart/issues/detail?id=4136
class FullscreenWorkaround {
static void requestFullscreen(Element element) {
_callMethods(element, [
'requestFullscreen',
'webkitRequestFullscreen',
'mozRequestFullScreen',
'msRequestFullscreen',
'oRequestFullscreen'
]);
}
static void exitFullscreen() {
_callMethods(document, [
'exitFullscreen',
'webkitExitFullscreen',
'mozCancelFullScreen',
'msExitFullscreen',
'oExitFullscreen'
]);
}
static bool get fullscreenEnabled {
var result = _getProperty(document, [
'fullscreenEnabled',
'webkitFullscreenEnabled',
'mozFullScreenEnabled',
'msFullscreenEnabled',
'oFullscreenEnabled'
]);
return result != null ? result : false;
}
static get fullscreenElement {
return _getProperty(document, [
'fullscreenElement',
'webkitFullscreenElement',
'mozFullScreenElement',
'msFullscreenElement',
'oFullscreenElement'
]);
}
static _callMethods(browserObject, List methods) {
var jsElem = new JsObject.fromBrowserObject(browserObject);
for (String methodName in methods) {
if (jsElem.hasProperty(methodName)) {
return jsElem.callMethod(methodName);
}
}
}
static _getProperty(browserObject, List properties) {
var jsElem = new JsObject.fromBrowserObject(browserObject);
for (String propertyName in properties) {
if (jsElem.hasProperty(propertyName)) {
return jsElem[propertyName];
}
}
}
}
Look at the following code snippet.
import "dart:mirrors";
class meta {
final String data;
const meta(this.data);
}
#meta("Tag")
doSomething() => print("You have to do something");
void main() {
doSomething();
}
How can I retrieve functions, that is market with metadata tags? In my example, I want to find out, which method is marked with meta tags.
you could do something like this:
void main() {
doSomething();
getMetaData();
}
void getMetaData() {
LibraryMirror currentLib = currentMirrorSystem().libraries.values.last;
currentLib.declarations.forEach((Symbol s, DeclarationMirror mirror) {
if(mirror.metadata.length > 0) {
print('Symbol $s has MetaData: "${mirror.metadata.first.reflectee.data}"');
}
});
}
This should give you:
You have to do something
Symbol Symbol("doSomething") has MetaData: "Tag"
You could also analyze your files from another project and use dart:mirrors on that file instead of inspecting the current library. Maybe libraries.values.last will not always return the current library - so you might need to change it. In my case it worked.
var decls = currentMirrorSystem().isolate.rootLibrary.declarations;
print(decls.keys.where((k) => decls[k] is MethodMirror &&
decls[k].metadata.where((k) => k.reflectee is meta).isNotEmpty));
see also How can i test the existence of a function in Dart?
I got this Dart Script below and I want to access the methods from the class hello_world by JavaScript after I compiled the Dart Script with dart2js.
Does anybody know how this works?!
I already know how to access the functions like foo(...), thats not the problem, but it does not work the same way with classes and methods.
And the tutorials on dartlang.org only explain how to access functions, not methods and classes.
I dont get it...
import 'dart:js' as js;
class hello_world {
String hello = 'Hello World!';
String getHello() {
print("getHello!!!!!");
return hello;
}
void ausgabe() {
print("Hallo Welt");
//return 0;
}
}
String foo(int n) {
print("hallo");
void foo2() {
print("hallo2");
}
//works
js.context['foo2'] = foo2;
return 'Hallo';
}
void main() {
int zahl1 = 3;
int zahl2 = 1234;
String w = 'test';
hello_world test = new hello_world();
//works
js.context['foo'] = foo;
}
Assuming you want to create a Js function bind on a Dart method you can do almost the same thing :
void main() {
hello_world test = new hello_world();
// define a 'getHelloOnTest' Js function
js.context['getHelloOnTest'] = test.getHello;
}
Now on Js side you can use :
getHelloOnTest();
I want to write some Dart function "oKey" which calls JavaScript function "jsOnKey" (with success or exception too since cannot predict).
Next I want that JavaScript function "onKey" will call Dart function "callbackFromJs" to return control to Dart again (with success or exception).
Can you help me with this full flow - please assume SUCCESS or EXCEPTION on each border - I can not rely on 3rd party code - DART 2 JS 2 DART?
To make more context to this general question I put example code.
import 'dart:html';
void onKey(Event event) {
// I want to call something in javascript
// function callbackFromDart () {
// /* something */;
// /* call callbackJs in Dart - return control to dart */
// }
}
void callbackFromJs() {
// It should be called from JavaScript
}
void main() {
InputElement nameElement = querySelector('input[name=name]');
nameElement..placeholder = 'Enter text'
..onKeyUp.listen(onKey);
InputElement descriptionElement = querySelector('input[name=description]');
descriptionElement..placeholder = 'Enter text'
..onKeyUp.listen(onKey);
}
First have a look at Using JavaScript from Dart.
For your case you can simply pass callbacks to handle what you call Js 2 Dart :
import 'dart:js' as js;
void onKey(Event event) {
onSuccess() {
// Dart callback called from Js
}
onError() {
// Dart callback called from Js
}
// assuming your js function takes 2 callbacks as parameters
try {
// in JS : function a() { throw "throw from js"; }
js.context.callMethod('myTopLevelFunction', [onSuccess, onError]);
}
catch (e) {
print('js error catch on Dart side : $e');
}
}
The Dart exceptions can be catch with the same kind of code on Js side.
How I can return Future value from Future object?
This code does not work.
import 'dart:async';
void main() {
var temp = foo();
temp.then((Future<int> future) {
future.then((int result) {
print(result);
});
});
}
Future<Future<int>> foo() {
return new Future<Future<int>>(() {
return new Future<int>(() => 5);
});
}
How to prevent unnecessary unwrapping?
In this case in async library 'Future' declared as generic class.
abstract class Future<T> {
}
If I create expression as the following
new Future<Future<int>>();
Then with type T specified as Future<int> which result expected from generic class Future?
I thing that result must be as specified in type argument T.
I.e. Future<int>.
But result is not as expected.
There is no information found about this abnormal behavior on Dart API site.
If this is a "feature" (but I think that abnormal behavior wrongly to call "feature') then why it not documented in Dart API?
How can be explained this discrepancy?
Why this code not generated errors and warnings?
Another IDENTICAL example but w/o using Future.
void main() {
var temp = foo();
temp.baz((Foo<int> foo) {
foo.baz((int result) {
print(result);
});
});
}
Foo<Foo<int>> foo() {
return new Foo<Foo<int>>(() {
return new Foo<int>(() => 5);
});
}
If in this case result will be as when using Future (i.e. unexpected) then how we can call this code?
Normal or abnormal?
Or maybe the Future in Dart some special (magic)?
Look at the api documentation
http://api.dartlang.org/docs/releases/latest/dart_async/Future.html
It says there:
If the returned value is itself a Future, completion of the created future will wait until
the returned future completes, and will then complete with the same result.
I guess that means you can't return a Future from a Future.
But you could return a list of futures.
void main() {
var temp = foo();
temp.then((List<Future<int>> list) {
list[0].then((int result) {
print(result);
});
});
}
Future<List<Future<int>>> foo() {
return new Future<List<Future<int>>>(() {
return [new Future<int>(() => 5)];
});
}
There is no need for any of that extra wrapping. According to the Future documentation:
If the returned value is itself a [Future], completion of the created
future will wait until the returned future completes, and will then
complete with the same result.
This means you can rewrite your code as:
import 'dart:async';
void main() {
var temp = foo();
temp.then((int result) {
print(result);
});
}
Future<int> foo() {
return new Future<int>(() {
return new Future<int>(() => 5);
});
}
This is a lot cleaner to work with and provides the expected result.