I would like to develop some of the webcomponents in a Polymer 2.0 project with scala.js. While there is a wonderful demo-project on github demonstrating how it works with Polymer 1.0. I cannot get something similar to work with Polymer 2.0 and the native Element-registration technique.
A simple facade might look like the following
@ScalaJSDefined
class PolymerElement extends PolymerBase {
def is: String = ""
def properties: js.Dynamic = js.Dynamic.literal()
}
@js.native
@JSGlobal("Polymer.Element")
class PolymerBase extends HTMLElement
The actual Element:
@JSExportTopLevel("MyElement")
@ScalaJSDefined
class MyElement extends PolymerElement {
private var label = "init"
override def is = "my-element"
override def properties = js.Dynamic.literal(
"label" -> Map(
"type" -> "String",
"value" -> "init",
"notify" -> true
).toJSDictionary
)
def testMe = {
println(label)
}
}
object MyElement {
@JSExportStatic
val is: String = MyElement.is
@JSExportStatic
val properties: js.Dynamic = MyElement.properties
}
No matter whether I take the old style element registration Polymer(MyElement)
or the platform native variant window.customElement.define(MyElement.is, MyElement)
It obviously throws an exception as MyElement
isn't instatiable with new MyElement
.
It throws the exception:
Uncaught TypeError: Class constructor PolymerElement cannot be invoked without 'new'
Studying the Scala.js facade writing guide, I already tried a lot of facade variants declaring PolymerElement
and PolymerBase
abstract.
A possible solution that comes to my mind is, writing a native JavaScript Class, that indeed is instantiable and using @js.native
facades on them. But I'm looking for a way to achieve it with something Scala.js 0.6.16 provides.
Ok, this is possible helps to someone else too and I decided to publish my new version of it.
I'm using this pure ScalaJS solution to integrate with Polymer2/CustomElements.
My environment is:
"org.scala-js" %%% "scalajs-dom" % "0.9.2"
ScalaJS options:
"-P:scalajs:sjsDefinedByDefault"
I've created some ScalaJS facades for CustomElements and Polymer 2 and published them here - https://bitbucket.org/latestbit/scalymer/src/tip/src/main/scala/org/latestbit/sjs/polymer2/?at=default
They're not full-featured Polymer facades, just in the very beginning state, but they are working for me.
And you can use them easily without any hacks like:
@JSExportTopLevel(name = "TestElement")
class TestElement() extends Polymer.Element {
override def connectedCallback(): Unit = {
super.connectedCallback()
global.console.log(s"Attribute name ${getAttribute("name")}. Body is ${dom.document.querySelector("body")}")
global.console.log(s"${this.$.selectDynamic("testCl")}")
global.console.log(s"${$$("testCl")}")
}
}
object TestElement {
@JSExportStatic
def is = "test-element"
@JSExportStatic
def properties = js.Dictionary(
"name" -> js.Dictionary(
"type" -> "String"
)
)
}
Then register it also in Scala like:
object TestJsApplication {
def main() : Unit = {
Globals.customElements.define(TestElement.is,
js.constructorOf[TestElement]
)
}
}
The html part is usual:
<dom-module id="test-element">
<template>
<span id="testCl">Not much here yet.</span>
This is <b>[[name]]</b>.
</template>
</dom-module>
You will find the complete example here - https://bitbucket.org/latestbit/scalymer/src
Ok, this is the best 'solution' I've found.
This is not solving it completely, but I hope it'll be a helpful trick while we're expecting sjs improvements in this area.
Get any library to 'mixin' js classes. I've used https://github.com/rse/aggregation.
Create your ScalaJS component but don't try to inherit it from Polymer.Element directly:
@ScalaJSDefined
@JSExportTopLevel("TestPolymerElement")
class TestPolymerElement extends js.Object {
def test = g.console.log("Hello from scala")
}
object TestPolymerElement {
@JSExportStatic
def is = "test-polymer-element"
}
class TestPolymerElementJs extends aggregation(Polymer.Element,TestPolymerElement) {
}
customElements.define(TestPolymerElementJs.is, TestPolymerElementJs);
Also, you can define the properties and manage them in ScalaJS like:
@ScalaJSDefined
@JSExportTopLevel("TestPolymerElement")
class TestPolymerElement(val name : String) extends js.Object {
def test = g.console.log(s"Hello from ${name}")
}
object TestPolymerElement {
@JSExportStatic
def is = "test-polymer-element"
@JSExportStatic
def properties = js.Dictionary (
"name" -> js.Dictionary(
"type" -> "String"
)
)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With