How do I create "options objects" in Scala.Js? - scala.js

In idiomatic JavaScript it's common to have a function accept an "options object" as the last parameter. This is where you'd usually put all the option/seldom-used parameters, e.g.
jQuery.ajax({
url: "http://www.example.com/foo",
success: function() {
..
}
})
The current documentation for Scala.JS recommands using a Scala trait to represent the options object, but that leads to a problem when you have to create the options since you cannot pass an anonymous class into JavaScript code.
How can such option objects be created from Scala code?

We recommend the following (if you chose to create facade-types):
trait AjaxOptions extends js.Object {
val url: String = js.native
val success: js.Function0[Unit] = js.native
}
object AjaxOptions {
def apply(url: String, success: js.Function0[Unit]): AjaxOptions = {
js.Dynamic.literal(url = url, success = success).asInstanceOf[AjaxOptions]
}
}
The advantage is that the type-unsafe cast is contained in a single location. Further, if you ever decide to add/remove fields to/from AjaxOptions, you will (hopefully) think of also adapting the companion's apply method. As a result, the typer will inform you where you have to change your invocations (rather than just having the new field set to undefined).
Please refer to What is the suggested way to instantiate a js.Object for API wrappers for more.

Since Scala.js has evolved, I'm amending my answer with the current best practice:
At this point, you should use a trait to describe the options object, like this:
trait AjaxOptions extends js.Object {
var url: String
var success: UndefOr[js.Function0[Unit]] = js.undefined
}
That UndefOr[T] means "this field might contain T, or might be undefined"; note that you are initializing those to js.undefined, so they have a default value.
Then, at the call site, you simply override the values that you need to set:
val ajaxResult = new AjaxOptions {
url = "http://www.example.com/foo"
}
Note the curly braces: you're actually creating an anonymous subclass of AjaxOptions here, that does what you want. Any fields you don't override (such as success above) get left as undefined, so the library will use its default.
Old Answer:
This question is pretty old, but since people are still coming here:
If you have a large and complex options object (as is typical of, say, jQuery UI classes), you may want to build a facade for that using JSOptionBuilder, which is found in the jsext library. JSOptionBuilder isn't quite a panacea, but it's a not-too-much boilerplate mechanism for constructing and using arbitrarily complex options objects.

Here's a method that I've found to work quite well:
val fooOptions = js.Dynamic.literal().asInstanceOf[FooOptions]
fooOptions.url = ...
fooOptions.bar = ...
jsFunc(..., fooOptions)
Of course this assumes that the FooOptions trait has declared the fields as var. If not, you'll have to use
val fooOptions = js.Dynamic.literal(
url = ...,
bar = ...,
)
jsFunc(..., fooOptions)
but that is less type-safe.
If you're declaring your own options trait, you could also add a companion object with an appropriate apply method:
trait FooOptions extends Js.Object {
var foo: js.String = ???
var bar: js.String = ???
}
object FooOptions {
def apply(): FooOptions =
js.Dynamic.literal().asInstanceOf[FooOptions]
}
That'll make calling code a lot prettier:
val fooOptions = FooOptions()
fooOptions.foo = ...
fooOptions.bar = ...
jsFunc(..., fooOptions)

Related

Scala object constructor

I have to create a file loader object and I would like the file to be loaded only once at object creation.
What I did until now is create a trait with a method read that will read file and output a list of String.
trait Loader {
protected val readSource: List[String] = {
Source
.fromInputStream(getClass.getResourceAsStream("filename"), "UTF-8")
.getLines()
.toList
}
def transform(delimeter: String): Vector[C] = {
val lines = readSource
// process the lines
}
}
The trait is implemented by several object, and the transform method can be called multiple times in the client code.
I would like to avoid re reading the file each time the transform method is called and my first solution was to extract the val lines = readSource from the transform method and make a function of it def loadFile = readSource and to create a apply method in my objects to call loadFile like so :
object MyLoader extends Loader {
def apply: List[String] = {
loadFile
}
}
I am wondering if this is the right way to do it. Thank you for your advices.
If you want the resource read once for all, then you should do that in a singleton object, which will be initialized once lazily.
Clients should use that object. "Prefer composition over inheritance" is the mantra.
If you want a mix-in that makes it easy to use the object, you can use "self-types" to constrain clients:
trait HasResource { val resource: R = TheResource }
trait Client { self: HasResource => def getR: R = resource }
This is the "cake pattern" way of making stuff available.

JavaScript object as function parameter

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))
}

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
}

How can I add new methods to a library object?

I've got a class from a library (specifically, com.twitter.finagle.mdns.MDNSResolver). I'd like to extend the class (I want it to return a Future[Set], rather than a Try[Group]).
I know, of course, that I could sub-class it and add my method there. However, I'm trying to learn Scala as I go, and this seems like an opportunity to try something new.
The reason I think this might be possible is the behavior of JavaConverters. The following code:
class Test {
var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}
does not compile, because there is no asScala method on Java's ArrayList. But if I import some new definitions:
class Test {
import collection.JavaConverters._
var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}
then suddenly there is an asScala method. So that looks like the ArrayList class is being extended transparently.
Am I understanding the behavior of JavaConverters correctly? Can I (and should I) duplicate that methodology?
Scala supports something called implicit conversions. Look at the following:
val x: Int = 1
val y: String = x
The second assignment does not work, because String is expected, but Int is found. However, if you add the following into scope (just into scope, can come from anywhere), it works:
implicit def int2String(x: Int): String = "asdf"
Note that the name of the method does not matter.
So what usually is done, is called the pimp-my-library-pattern:
class BetterFoo(x: Foo) {
def coolMethod() = { ... }
}
implicit def foo2Better(x: Foo) = new BetterFoo(x)
That allows you to call coolMethod on Foo. This is used so often, that since Scala 2.10, you can write:
implicit class BetterFoo(x: Foo) {
def coolMethod() = { ... }
}
which does the same thing but is obviously shorter and nicer.
So you can do:
implicit class MyMDNSResolver(x: com.twitter.finagle.mdns.MDNSResolver) = {
def awesomeMethod = { ... }
}
And you'll be able to call awesomeMethod on any MDNSResolver, if MyMDNSResolver is in scope.
This is achieved using implicit conversions; this feature allows you to automatically convert one type to another when a method that's not recognised is called.
The pattern you're describing in particular is referred to as "enrich my library", after an article Martin Odersky wrote in 2006. It's still an okay introduction to what you want to do: http://www.artima.com/weblogs/viewpost.jsp?thread=179766
The way to do this is with an implicit conversion. These can be used to define views, and their use to enrich an existing library is called "pimp my library".
I'm not sure if you need to write a conversion from Try[Group] to Future[Set], or you can write one from Try to Future and another from Group to Set, and have them compose.