If I want to use Dart to create a js library, how can I export Dart classes and functions for use in javascript?
Is there something similar to scala.js, like this?
#JSExport
class Hello{
num x = 0
Hello(this.x)
}
So that in javascript, users can instantiate it as var hi = new Hello(1)
In case this is still relevant: You can use the dart2js compiler, which will compile your dart code down to ES.
Related
I am planing to use semantic ui modal has anyone any idea, how to interoperate with dart?
Use the js package to interoperate. First, add the package as a dependency. Then, wrap the JavaScript that you want to use from Dart. Here's an example allowing you to use jQuery's $(...).addClass(...) in Dart:
#JS()
library jquery;
import 'package:js/js.dart';
// Calls invoke JavaScript `JSON.stringify(obj)`.
#JS("\$")
external ElementSet $(String selector);
#JS()
class ElementSet {
external addClass(String className);
}
If you import this file, you can now do:
$('#output').addClass("red");
That example is, of course, quite useless — Dart already allows you to modify HTML classes with better readability and flexibility (e.g. querySelector('#output').classes.add("red")).
But in your case, it starts to make sense. You would implement modal() and go from there.
(I would give you an example of how to implement modal, but I wasn't able to install semantic ui on my workstation for 10+ minutes and then I gave up. So I used the jQuery.addClass example instead.)
It's not that easy. There are two or three pub packages available but they are outdated and incomplete.
I did it this way in Dart 2 (AngularDart 5):
import 'dart:js';
// somewhere in the component:
context
.callMethod(r'$', [modalSelector])
.callMethod('modal', [new JsObject.jsify({
'onApprove': new JsFunction.withThis((element){
// do something on approve
})
})])
.callMethod('modal', ['show']);
This Dart code is equivalent to this Javascript code:
$(modalSelector).modal({
'onApprove': function(element){
// do something on approve
})
.modal('show');
As you may see, you have to call the jQuery framework through the JS module.
I am moving java script to dart, in java script I create dynamic variable like
window["text" + pageNumber] = 123;
alert(window["text" + pageNumber]);
How can I do it with dart?
In Dart Window (the type of window) is a class. You can't dynamically add properties to a Dart class.
window["text" + pageNumber] = 123; would work with a Map. Object representation in JS is quite similar to a map and therefore this works there.
If another class implements the [] operator you could call it on instances of that class as well but it would still not add properties. What it actually does just depends on the implementation of the [] operator.
There are probably different ways in Dart to achieve what you want, but you didn't add details about what actual problem you try to solve.
You can use normal global variables in Dart like explained in
Global Variables in Dart.
For your use case you can create a global Map variable this way
final Map<String,int> myGlobals = <String,int>{};
to create a map that stores integer values with string names.
Set values with myGlobals['someName'] = 123; and read them with print(myGlobals['someName']);.
If you need to set a global value that is also available for JS libraries you might use, you can use dart-js-interop
import 'dart:js';
import 'dart:html';
main() {
int pagenumber = 5;
context['Window']['text$pagenumber'] = 123;
window.alert('${context['Window']['text$pagenumber']}');
}
Try it on DartPad.
Hint:
"text" + pageNumber doesn't work when pageNumber is not a string.
In Dart you can't add string and numbers.
"text" + pageNumber.toString() would work but 'text$pagenumber' is a more darty way to do this. In string interpolation toString() is called automatically for you.
See also Dart js-interop not working if .dart file isn't included.
I often see people use the keyword using in their Haxe code. It seem to go after the import statements.
For example, I found this is a code snippet:
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
using haxe.macro.Tools;
using Lambda;
What does it do and how does it work?
The "using" mixin feature of Haxe is also referred as "static extension". It's a great syntactic sugar feature of Haxe; they can have a positive effect on code readability.
A static extension allows pseudo-extending existing types without modifying their source. In Haxe this is achieved by declaring a static method with a first argument of the extending type and then bringing the defining class into context through the using keyword.
Take a look at this example:
using Test.StringUtil;
class Test {
static public function main() {
// now possible with because of the `using`
trace("Haxe is great".getWordCount());
// otherwise you had to type
// trace(StringUtil.getWordCount("Haxe is great"));
}
}
class StringUtil {
public static inline function getWordCount(value:String) {
return value.split(" ").length;
}
}
Run this example here: http://try.haxe.org/#C96B7
More in the Haxe Documentation:
Haxe static extensions in the Haxe Manual
Haxe static extensions tagged articles in the Haxe Code Cookbook
I have a Java 7 project which makes a lot of use of Javascript for scripting various features. Until now I was using Rhino as script engine. I would now like to move to Java 8, which also means that I will replace Rhino by Nashorn.
How compatible is Nashorn to Rhino? Can I use it as a drop-in replacement, or can I expect that some of my scripts will not work anymore and will need to be ported to the new engine? Are there any commonly-used features of Rhino which are not supported by Nashorn?
One problem is that Nashorn can no longer by default import whole Java packages into the global scope by using importPackage(com.organization.project.package);
There is, however, a simple workaround: By adding this line to your script, you can enable the old behavior of Rhino:
load("nashorn:mozilla_compat.js");
Another problem I ran into is that certain type-conversions when passing data between java and javascript work differently. For example, the object which arrives when you pass a Javascript array to Java can no longer be cast to List, but it can be cast to a Map<String, Object>. As a workaround you can convert the Javascript array to a Java List in the Javascript code using Java.to(array, Java.type("java.util.List"))
To use the importClass method on JDK 8, we need to add the following command:
load("nashorn:mozilla_compat.js");
However, this change affect the execution on JDK 7 (JDK does not gives support to load method).
To maintain the compatibility for both SDKs, I solved this problem adding try/catch clause:
try{
load("nashorn:mozilla_compat.js");
}catch(e){
}
Nashorn can not access an inner class when that inner class is declared private, which Rhino was able to do:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class Test {
public static void main(String[] args) {
Test test = new Test();
test.run();
}
public void run() {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
Inner inner = new Inner();
engine.put("inner", inner);
try {
engine.eval("function run(inner){inner.foo(\"test\");} run(inner);");
} catch (ScriptException e) {
e.printStackTrace();
}
}
private class Inner {
public void foo(String msg) {
System.out.println(msg);
}
}
}
Under Java8 this code throws following exception:
javax.script.ScriptException: TypeError: kz.test.Test$Inner#117cd4b has no such function "foo" in <eval> at line number 1
at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:564)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:548)
I noticed that Rhino didn't have a problem with a function called 'in()' (although 'in' is a reserved JavaScript keyword).
Nashorn however raise an error.
Nashorn cannot call static methods on instances! Rhino did this, therefore we had to backport Rhino to Java 8 (Here's a short summary: http://andreas.haufler.info/2015/04/using-rhino-with-java-8.html)
Nashorn on Java8 does not support AST. So if you have Java code that inspects the JS source tree using Rhino's AST mechanism , you may have to rewrite it (using regex maybe) once you port your code to use Nashorn.
I am talking about this API https://mozilla.github.io/rhino/javadoc/org/mozilla/javascript/ast/AstNode.html
Nashorn on Java9 supports AST though.
One feature that is in Rhino and not Nashorn: exposing static members through instances.
From http://nashorn-dev.openjdk.java.narkive.com/n0jtdHc9/bug-report-can-t-call-static-methods-on-a-java-class-instance : "
My conviction is that exposing static members through instances is a
sloppy mashing together of otherwise separate namespaces, hence I
chose not to enable it.
I think this is deeply wrong. As long as we have to use two different constructs to access the same java object and use package declarations unnecessarily in javascript, code becomes harder to read and write because cognitive load increases. I will rather stick to Rhino then.
I have not found a workaround for this obvious "design bug" yet.
No, this isn't the same as the other question of the same name.
There are seemingly identical packages which seem to do this, but with different apis.
http://dart-lang.github.io/js-interop/docs/js.html
https://api.dartlang.org/docs/channels/stable/latest/dart_js.html
Why are there two?
Which one are we supposed to use?
The interop one looks newer and has a better api, but doesn't actually work. According to the documentation, you should be able to convert this javascript:
var stage = new PIXI.Stage(0xFFFFFF);;
renderer = PIXI.autoDetectRenderer(800, 600);
document.body.appendChild(renderer.view);
Into:
var pixi = new js.Proxy(js.context.PIXI.Stage, 0xffffff);
var renderer = js.context.PIXI.autoDetectRenderer(400, 400);
document.body.append(renderer.view);
But that errors when you try to compile it:
dart2js
Error occured:/Users/doug/megac/client/public/dart/index.dart:7:27:
Warning: No member named 'PIXI' in class 'Proxy'.
var pixi = new js.Proxy(js.context.PIXI.Stage, 0xffffff);
^^^^^^^^^^^^^^^
So... js:dart? Is that what you're supposed to use?
Edit: Incidentally, for anyone who stumbles into this, there is also an open bug http://code.google.com/p/dart/issues/detail?id=15795&thanks=15795&ts=1388068177 regarding how minified dart-js interop bridge operations don't currently work. The original issue was reported in May 2013, and there's been no action on it since then, so don't hold your breath.
Js interop started with package:js. It was built with with window.postMessage.
Later dart:js has been added to provide better performance and reduce the size of the compiled js file. Basically the goal were :
removing scopes and lifecycle manual handling
avoiding noSuchMethod to keep compilation size as low as possible
renaming objects to make the api more understandable
Once dart:js has been ready, package:js has been rewrite to use dart:js under the cover.
package:js provides a simpler Api that comes at the cost of an increase of the js size (because package:js uses dart:mirrors and noSuchMethod).
Here is the same thing done with package:js and dart:js :
import 'package:js/js.dart' as js;
main() {
var pixi = new js.Proxy(js.context.PIXI.Stage, 0xffffff);
var renderer = js.context.PIXI.autoDetectRenderer(400, 400);
document.body.append(renderer.view);
}
import 'dart:js' as js;
main() {
var pixi = new js.JsObject(js.context['PIXI']['Stage'], [0xffffff]);
var renderer = js.context['PIXI'].callMethod('autoDetectRenderer', [400, 400]);
document.body.append(renderer['view']);
}