
Copyright © Cay S. Horstmann 2015 
This work is licensed under a Creative Commons Attribution 4.0 International License

@JSExport
object ScalaJSExample {
@JSExport
def main(canvas: html.Canvas) {
val ctx = canvas.getContext("2d")
.asInstanceOf[dom.CanvasRenderingContext2D]
ctx.fillRect(0, 0, 100, 100)
}
}cxt.fillRect are typesafe, can use IDE autocompletion@JSExport 
This follows the excellent tutorial by Li Haoyi
git clone https://github.com/lihaoyi/workbench-example-app, or if for whatever reason, you don't have git on your computer, download and unzip this zip file.In a command shell, type
cd workbench-example-app ../activator-1.3.2/activator ~fastOptJS(adjusting the directory paths and version number if necessary)
sbt. The activator is a superset of the sbt tool.
1. Waiting for source changes... (press enter to interrupt)point your browser to http://localhost:12345/target/scala-2.11/classes/index-dev.html. What happens?
workbench-example-app/project/build.sbt and add a line
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "3.0.0")
to the end. Run
../activator-1.3.2/activator eclipseThen run the Scala IDE and import the project at
workbench-example-app.Run
../activator-1.3.2/activator ~fastOptJSagain. In the IDE, find the file
src/main/scala/example/ScalaJSExample. You'll find the source code for the fractal, which isn't very illuminating. Let's do something simpler instead. Change the run method to
def run = {
count += 1
ctx.fillStyle = "green"
ctx.fillRect(0, 0, count, 100)
} Refresh your browser window. What happens? Why?
for/yield anywhere. Let's fix that. We want to draw a bar chart, like this:
val data = List(2, 3, 5, 7, 11, 13)For now, comment out the line
dom.setInterval(() => run, 50)Add this class
case class Rect(x: Double, y: Double, width: Double, height: Double) {
def fill(ctx: CanvasRenderingContext2D) { ctx.fillRect(x, y, width, height)}
}
and transform data to a list of Rect, using for/yield. Put the code outside the run method. What is your code?rects foreach { _.fill(ctx) }
and refresh the browser. Did it work?println(rects). Where do you think the printout shows up? (Hint: It's JavaScript—look into the console of your browser dev tools...)
def main(target: html.Div) = {
var p = document.createElement("p")
val t = document.createTextNode("Hello, World!")
p.appendChild(t)
target.appendChild(n)
}
jQuery instead of $:
target.append(jQuery("<p/>").text("Hello, World"))
Ajax.get(url).onSuccess { case xhr =>
val str = xhr.responseText
...
}JSON.parse turns response string into an object of type scalajs.js.Dynamicval response = JSON.parse(xhr.responseText) // has type Dynamic val tasks = response.tasks // Works if JSON has field with name "tasks"
val tasksAsArray = tasks.asInstanceOf[scalajs.js.Array[String]] // Works if it was a JavaScript array of strings

ScalaJSExample.scala file so that it contains
package example
import org.scalajs.dom
import dom.html
import scalajs.js.annotation.JSExport
@JSExport
object ScalaJSExample {
@JSExport
def main(target: html.Div) ={
target.innerHTML = s"""
<div>
<h1>Hello World!</h1>
</div>
"""
}
}In resources/index-dev.html, change the div containing the canvas into
<div id='div'></div>and in the call to
getElementById, change canvas to div. Reload the page. What happens? main:
import dom.document
val items = List("Hello", "World")
var n1 = document.createElement("ul")
for (i <- items) {
val t = document.createTextNode(i)
val n = document.createElement("li")
n.appendChild(t)
n1.appendChild(n)
}
target.appendChild(n1)
What happens? Why?resources/index-dev.html, add
<script type="text/javascript" src="http://cdn.jsdelivr.net/jquery/2.1.3/jquery.js"></script>inside the
head element. In workbench-example-app/build.sbt (not the project/build.sbt file!), add
, "be.doeraene" %%% "scalajs-jquery" % "0.8.0"to the
Seq of library dependencies. Then
import to the top of ScalaJSExample.scala:
import org.scalajs.jquery._You should get an error message about an unknown import.
../activator-1.3.2/activator and type
reload eclipse ~fastOptJS
main with
val items = List("Hello", "World")
var n1 = jQuery("<ol/>").appendTo(jQuery("#div"))
for (i <- items)
n1.append(jQuery("<li/>").text(i))
Reload. What happens?div in index-dev.html to
<h1>Capital Box!</h1> <p id='cap'>Type below and have it capitalized!</p> <input id='box' type="text" value='Type here'>Change the contents of
main to
val box = jQuery("#box")
box.keyup((ev: JQueryEventObject) => {
val t = box.value()
jQuery("#cap").text(t.toString().toUpperCase())
})box? What is the type of t?toString necessary?JQueryEventObject parameter type be inferred?unit15 directory (or whereever you had it), and pointing a browser to http://localhost:9000. Add a few tasks. package controllers
import play.api._
import play.api.mvc._
import play.api.libs.json._
import models.Task
object Api extends Controller {
def tasks = Action {
Ok(Json.toJson(Json.obj("tasks" -> Task.all().map(t => Json.obj("id" -> t.id, "label" -> t.label)))))
}
} and a route
GET /api/tasks controllers.Api.tasksPoint a browser window to
http://localhost:9000/api/tasks. What do you get? Why?div to
<div id='div'> <ul id='tasks'> </ul> </div>and the
main method to
val tasks = jQuery("#tasks")
val prefix = "http://localhost:9000/api/"
val url = prefix + "tasks"
def updateTasks() {
tasks.empty()
Ajax.get(url).onSuccess { case xhr =>
JSON.parse(xhr.responseText).tasks.asInstanceOf[scalajs.js.Array[scalajs.js.Dynamic]] map { t =>
val task = jQuery("<li/>")
task.text(t.label.asInstanceOf[String])
tasks.append(task)
}
}
}
updateTasks()
Add this to the top of the Scala file:
import dom.ext._ import scalajs.js.JSON import scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
--disable-web-security. Point it to http://localhost:12345/target/scala-2.11/classes/index-dev.html. What happens now? val button = jQuery("<input type='button' value='Delete' style='margin: 0.2em'/>")
task.append(button)
button.click((ev: JQueryEventObject) => {
Ajax.post(prefix + "tasks/" + t.id + "/delete", "").onSuccess { case xhr =>
println(xhr.responseText)
}
})
Where do you put it?POST /api/tasks/:id/delete controllers.Api.deleteTask(id: Long)and a method
def deleteTask(id: Long) = Action {
Task.delete(id)
Ok("deleted " + id)
} Now what happens when you delete a task?updateTasks.)<p>Label <input id='label' type="text"/> <input id='create' type="button" value="Create"/></p>And add a button handler:
jQuery("#create").click((ev: JQueryEventObject) => {
val label = jQuery("#label").value().toString
Ajax.post(prefix + "tasks/" + label + "/create", "").onSuccess { case xhr =>
println(xhr.responseText)
updateTasks()
}
})
What will happen when you click the button?newTask from Unit 15. (It's a bit wrong to put the label into the URL—it really should go with the POST data, but that's not so easy due to the immaturity of the libraries, so we'll skip it.) What did you do to make creating new tasks possible?This was a cutting-edge lab, and there were two weak points. The transfer of data between the client and server are not really satisfactory. As already mentioned, that's something that can be fixed with some libraries.
But what is less satisfactory is running two projects and hacking the browser to allow connections to two ports. We just didn't have the time in the lab to do this right. Your homework assignment is to fix it.
Follow this or this post and deliver a single project that includes both the Play app and the Scala JS client. Make it so that connecting to localhost:9000 serves up the single page of the app.