JavaScript object as function parameter - scala.js

I'm writting a function transpiled with Scala.js that should accept any random JavaScript object.
Ex:
// This has been transpiled using Scala.js
var my_service = new com.myself.Service();
// This is plain JavaScript
var result1 = service({ hello: "yolo" });
var result2 = service({ whatever: "ok", really: { yes: "right", no: "don't" } });
However, I can't find the input type that matches it.
What would be the Scala-function signature to get such a thing?
Could it be used then as a "Scala/JS case class" easily?
Note (if it helps giving a direction for the answers): these objects have, in the real life, an expected schema but it cannot be created as JS object generated from Scala.js since it comes from another consumed service.

Since the objects have an expected schema, its probably easiest to define a facade type:
#js.native
trait Args extends js.Object {
val hello: js.UndefOr[String]
val whatever: js.UndefOr[String]
val really: js.UndefOr[ReallyArgs]
}
#js.native
trait Really extends js.Object {
val yes: String
val no: String
}
def myMethod(args: Args): Unit = {
println(args.hello)
println(args.really.map(_.yes))
}

Related

How to override the toString() method on JS objects to use JSON.stringify()?

I'm tired of writing blah: "${JSON.stringify(target)}" when I deal with my DTO objects, I just want to write blah: "$target".
My DTOs look like:
#js.native
trait AuthConnectionDetails extends js.Object {
def clientId: String = js.native
def accountHostname: String = js.native
}
These DTOs are used to parse the content of some REST API calls, like:
val response = js.JSON.parse(xmlHttpRequest.responseText).
asInstanceOf[AuthConnectionDetails]
I don't mind changing how I define my DTO objects to do this (maybe I should be using case classes for my DTOs or something, instead of native js traits?), but I can't figure out how to do it.
I tried writing a trait that I could mixin, but that didn't work and I tried writing an implicit extension method but that didn't work either.
My implicit code that didn't seem to work for toString:
object JsonToString {
implicit class JsObjectExtensions(val target: js.Object) extends AnyVal {
override def toString:String = JSON.stringify(target)
def json:String = JSON.stringify(target)
}
}
So I can do blah: "${target.json}", which is better - but I'd especially like to get rid of those braces.
Is there any way to do this with scala.js?
No, there is no way to do this. That's because string interpolation will always use the toString() method of the object itself, no matter what is declared in its types or in implicit classes (this is a Scala thing in general).
The only way you could achieve this would be to actually modify the objects by patching them up with a custom toString() method every time you create one. That would include when you parse them from a JSON string. I'm pretty sure that would be worse than calling .json when you stringify them.
If you really want to, you could write your custom string interpolator:
implicit class JsonHelper(private val sc: StringContext) extends AnyVal {
def dejson(args: Any*): JSONObject = {
sc.checkLengths(args)
s(args.map(jsonify))
}
private def jsonify(arg: Any) = arg match {
case obj: js.Object => JSON.stringify(obj)
case _ => arg.toString
}
}
You can now use this like this:
dejson"hello: $target, world: $target2"

How do I create optional "options" in a facade?

I am trying to create a facade for the bootstrap popover function that can take up to 11 optional parameters. In my scalajs code I would like to only pass in the parameters I need to override from library maintained sensible defaults ie: PopoverOptions(animation = false) just like I would do in javascript. This seems to be the recommend way to make a facade but it makes all the parameters required:
trait PopoverOptions extends js.Object {
val animation: String = js.native
val container: String = js.native
val content: String = js.native
...
}
object PopoverOptions {
def apply(animation: String, container: String, content: String, ...): PopoverOptions = {
js.Dynamic.literal(animation=animation, container= container, content = content, ...).asInstanceOf[PopoverOptions ]
}
}
It looks like one way is to define an apply for every possible permutation of parameters but when there are lots of override parameters this gets excessive quick:
def apply(animation: String): ...
def apply(container: String): ...
def apply(animation: String, container: String): ...
...
What is the idiomatic way to create an options parameter facade with lots of override parameters that typically have sensible library maintained defaults?
Note: both answers have pros/cons so to decide it might be helpful to see both ways without leaving SO so here is a summary of JSOptionBuilder method:
import org.querki.jquery.JQuery
import org.querki.jsext._
#js.native
trait PopoverOptions extends js.Object
object PopoverOptions extends PopoverOptionBuilder(noOpts)
class PopoverOptionBuilder(val dict:OptMap) extends JSOptionBuilder[PopoverOptions, PopoverOptionBuilder](new PopoverOptionBuilder(_))
{
def animation(v:String) = jsOpt("animation", v)
def container(v:String) = jsOpt("container", v)
def content(v:String) = jsOpt("content", v)
...
}
To use: PopoverOptions.animation("yay").container("container").content("bottom")._result
You can use Scala's default values for parameters, combined with js.UndefOrs of the types of elements, like this:
object PopoverOptions {
#inline
def apply(
animation: js.UndefOr[String] = js.undefined,
container: js.UndefOr[String] = js.undefined,
content: js.UndefOr[String] = js.undefined,
...): PopoverOptions = {
val result = js.Dynamic.literal()
animation.foreach(result.animation = _)
container.foreach(result.container = _)
content.foreach(result.content = _)
...
result.asInstanceOf[PopoverOptions]
}
}
Then you can call with PopoverOptions(animation = false), as you wished.
It's a bit verbose at definition site, but it will get the job done.
The alternative approach is to use JSOptionBuilder, which was created for this purpose. (I write many jQuery facades, and they always have this problem.) JSOptionBuilder isn't quite as critical as it used to be (this was a major problem before the "|" operator was introduced), but I still find it's usually the best way to deal with complex facades.
Here's the full description of this approach. (Note that that's enormously detailed -- the first half is the key stuff, and the rest deals with all the somewhat-common edge cases.)

Dynamic calls to JavaScript in Scala.js

I am wondering how to do dynamic operations in Scala.js. For example, looking at the jQuery example in the tutorial, my understanding is you define the following in scala:
object TutorialApp extends JSApp {
def appendPar(msg: String) = {
jQuery("body").append("<p>" + msg + "</p>")
}
def main(): Unit = {
appendPar("Hello World")
}
}
This is all stuff that is generated statically at compile time. But I didn't see any way I could set the message parameter dynamically (eg read it from a DB).
I don't know about reading it from the DB. That is beyond the scope of this question (or you need to rephrase the question). Maybe an AJAX call or something?
But to read it from, for example, an <input> tag, you'd do something like that:
def main(): Unit = {
val msg = jQuery("#myinput").value()
appendPar(msg)
}
(Although in this case it probably doesn't make any sense in a main method, but that's not the point.)
I mean, msg is just a val (so like a var in JS but immutable). You can fetch it from any dynamic source of information as you like.
Edit:
If you want to access some data generated dynamically by the server when rendering the page, you can do so like this:
First, have your server generate the data as a global var in a <script> tag in the generated HTML. Something like:
<script type="text/javascript">
var mydata = {
msg: "Some text generated dynamically by the server"
}
</script>
Make sure to emit this script tag before the call to the main() function of Scala.js!
Then, from Scala.js, you can access these data with the js.Dynamic interface:
import scala.scalajs.js
val mydata = js.Dynamic.global.mydata
val msg = mydata.msg.asInstanceOf[String]
If your data have always a relatively static structure, it may be useful to declare yourself a facade type for them:
#JSName("mydata")
object MyData extends js.Object {
val msg: String = ???
}
Then you can access it without resorting to the Dynamic API:
val msg = MyData.msg
Adding to (and attempting to generalize) sjrd's answer: To call a javaScriptMethod on an object of a JavaScriptType you first write a type facade for it:
import scala.scalajs.js
import scala.scalajs.js.annotation.JSName
#js.native
#JSName("JavaScriptType")
class MyType() extends js.Object {
def javaScriptMethod(someParam: String) = js.native
}
After that, it's a piece of cake to use the JavaScript code using Scala on the client side:
val myObject = new MyType()
myObject.javaScriptMethod("Yippie")
As a concrete example, to use Stack Overflow's Markdown converter Pagedown in your Scala.js application you'd first create the type facade for it:
#js.native
#JSName("Markdown.Converter")
class MarkdownConverter() extends js.Object {
def makeHtml(txtUsingMarkdown: String): String = js.native
}
If you are learning Scala.js using this great tutorial project, you can declare the dependency on Pagedown in Settings.scala like this:
val jsDependencies = Def.setting(Seq(
"org.webjars.bower" % "pagedown" % "1.1.0" / "Markdown.Converter.js",
//...
Then you can simply do
val html = new MarkdownConverter().makeHtml("this is *nice*")
Here's another example where we call a static method of SparkMD5.
We define an object as opposed to the class of the previous example. Also, we can omit the #JSName annotation since our Scala type is eponymous with the JavaScript type:
#js.native
object SparkMD5 extends js.Object {
def hash(str: String, raw: Boolean = false): String = js.native
}

What is this Scala 'new' syntax

From the ScalaTest docs:
class ExampleSpec extends FlatSpec {
def fixture =
new {
val builder = new StringBuilder("ScalaTest is ")
val buffer = new ListBuffer[String]
}
...
I don't understand how the new keyword is being used here. fixture is obviously a function, which declares and returns... what? It seems to be an object, since it has members (builder & buffer) that can be accessed with . notation.
Is what is being created here an anonymous class that is a subclass of AnyRef?
Yep, it returns instance of anynomous class. It is not hard to check it by yourself in REPL session:
scala> def fixture = new { val string = "mr. String" }
fixture: Object{val string: String}
Java can do the essentially same thing, believe it or not. The following is valid Java
(new Object() {
public void sayHello() {
System.out.println("hello!");
}
}).sayHello();
The Java version is just a mildly more verbose syntax and has a type system limitation that makes it mostly useless.
More about it here http://james-iry.blogspot.com/2009/04/java-has-type-inference-and-refinement.html

How do I create a class hierarchy of typed factory method constructors and access them from Scala using abstract types?

(Essentially I need some kind of a synthesis of these two questions (1, 2), but I'm not smart enough to combine them myself.)
I have a set of JAXB representations in Scala like this:
abstract class Representation {
def marshalToXml(): String = {
val context = JAXBContext.newInstance(this.getClass())
val writer = new StringWriter
context.createMarshaller.marshal(this, writer)
writer.toString()
}
}
class Order extends Representation {
#BeanProperty
var name: String = _
...
}
class Invoice extends Representation { ... }
The problem I have is with my unmarshalling "constructor" methods:
def unmarshalFromJson(marshalledData: String): {{My Representation Subclass}} = {
val mapper = new ObjectMapper()
mapper.getDeserializationConfig().withAnnotationIntrospector(new JaxbAnnotationIntrospector())
mapper.readValue(marshalledData, this.getClass())
}
def unmarshalFromXml(marshalledData: String): {{My Representation Subclass}} = {
val context = JAXBContext.newInstance(this.getClass())
val representation = context.createUnmarshaller().unmarshal(
new StringReader(marshalledData)
).asInstanceOf[{{Type of My Representation Subclass}}]
representation // Return the representation
}
Specifically, I can't figure out how to attach these unmarshalling methods in a typesafe and DRY way to each of my classes, and then to call them from Scala (and hopefully sometimes by using only abstract type information). In other words, I would like to do this:
val newOrder = Order.unmarshalFromJson(someJson)
And more ambitiously:
class Resource[R <: Representation] {
getRepresentation(marshalledData: String): R =
{{R's Singleton}}.unmarshalFromXml(marshalledData)
}
In terms of my particular stumbling blocks:
I can't figure out whether I should define my unmarshalFrom*() constructors once in the Representation class, or in a singleton Representation object - if the latter, I don't see how I can automatically inherit that down through the class hierarchy of Order, Invoice etc.
I can't get this.type (as per this answer) to work as a way of self-typing unmarshalFromJson() - I get a compile error type mismatch; found: ?0 where type ?0 required: Representation.this.type on the readValue() call
I can't figure out how to use the implicit Default[A] pattern (as per this answer) to work down my Representation class hierarchy to call the singleton unmarshalling constructors using type information only
I know this is a bit of a mammoth question touching on various different (but related) issues - any help gratefully received!
Alex
The key is to not try and attach the method to the class but rather pass it in as a parameter. To indicate the type you are expecting and let the type system handle passing it in. I tried to make the unmarshal invocation something that reads a little DSL like.
val order = UnMarshalXml( xml ).toRepresentation[Order]
The following is a fully testable code snippet
abstract class Representation {
def marshalToXml(): String = {
val context = JAXBContext.newInstance(this.getClass)
val writer = new StringWriter
context.createMarshaller.marshal(this, writer)
writer.toString
}
}
#XmlRootElement
class Order extends Representation {
#BeanProperty
var name: String = _
}
case class UnMarshalXml( xml: String ) {
def toRepresentation[T <: Representation](implicit m:Manifest[T]): T = {
JAXBContext.newInstance(m.erasure).createUnmarshaller().unmarshal(
new StringReader(xml)
).asInstanceOf[T]
}
}
object test {
def main( args: Array[String] ) {
val order = new Order
order.name = "my order"
val xml = order.marshalToXml()
println("marshalled: " + xml )
val received = UnMarshalXml( xml ).toRepresentation[Order]
println("received order named: " + received.getName )
}
}
You should see the following output if you run test.main
marshalled: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><order><name>my order</name></order>
received name: my order
Here's the updated version of Neil's code which I used to support the second use case as well as the first:
case class UnmarshalXml(xml: String) {
def toRepresentation[T <: Representation](implicit m: Manifest[T]): T =
toRepresentation[T](m.erasure.asInstanceOf[Class[T]])
def toRepresentation[T <: Representation](typeT: Class[T]): T =
JAXBContext.newInstance(typeT).createUnmarshaller().unmarshal(
new StringReader(xml)
).asInstanceOf[T]
}
This supports simple examples like so:
val order = UnmarshalXml(xml).toRepresentation[Order]
But also for abstract type based usage, you can use like this:
val order = UnmarshalXml(xml).toRepresentation[T](typeOfT)
(Where you have grabbed and stored typeOfT using another implicit Manifest at the point of declaring T.)