Reputation: 4284
I have a simple Scala.js class (Scala-2.12.10 and Scala-js 0.6.31):
class Foo extends js.Object {
def apply() = { println("apply") }
def bar() = { println("bar") }
}
val myfoo = new Foo()
An instance of Foo will be passed to a JavaScript library which will in turn attempt to invoke the following two methods:
myfoo()
myfoo.bar()
Of course, this will not work because I cannot define the apply
method on Foo since it derives from js.Object
and that will not translate to calling ()
on the object.
How does one construct an appropriate class for this scenario?
Update:
Here is some example code based on @sjrd's answer that provides for strong typing while encapsulating the js.Dynamic
complexity.
trait FooTrait extends js.Object {
def own()
def bar()
}
class Foo extends FooTrait {
def own() = { println("apply") }
def bar() = { println("bar") }
}
def makeFoo(foo: FooTrait]) = {
val jsFoo = ({ () =>
foo.own()
}: js.Function0[Unit]).asInstanceOf[js.Dynamic]
jsFoo.bar = ({ () =>
foo.bar()
}: js.Function0[Unit])
jsFoo
}
val myFoo = makeFoo(new Foo())
Now myFoo
is ready to be passed to the JavaScript library.
Upvotes: 1
Views: 116
Reputation: 22085
In JavaScript, the only way that a call like myfoo()
can be valid is if myfoo
was created as a function value. To make myfoo.bar()
work in addition, that must be patched on the function value after it's created. There is no way (except proxies, which are another beast entirely) to create myfoo
as an object first, from a class or not, and make it answer to myfoo()
.
Therefore, this is also what you have to do in Scala.js:
val myfoo = ({ () =>
println("apply")
}: js.Function0[Unit]).asInstanceOf[js.Dynamic]
myfoo.bar = ({ () =>
println("bar")
}: js.Function0[Unit])
After that, you can pass myfoo
to the JavaScript code.
Upvotes: 1