Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic calls to JavaScript in Scala.js

Tags:

scala

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

like image 268
user79074 Avatar asked Jan 21 '15 14:01

user79074


2 Answers

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
like image 139
sjrd Avatar answered Oct 15 '22 18:10

sjrd


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
}
like image 3
Matthias Braun Avatar answered Oct 15 '22 17:10

Matthias Braun