summaryrefslogtreecommitdiff
path: root/book/src/main/scalatex/book/handson/WebPage.scalatex
diff options
context:
space:
mode:
authorLi Haoyi <haoyi@dropbox.com>2014-11-10 21:10:07 -0800
committerLi Haoyi <haoyi@dropbox.com>2014-11-10 21:10:07 -0800
commit8ced367e0d736b429f0b39ae7fde2b76b1d64ed5 (patch)
treee1154648219f8367c2537580f207e8f100e75590 /book/src/main/scalatex/book/handson/WebPage.scalatex
parent2846d28c95d183792d6d809d1c3884b619b6f937 (diff)
downloadhands-on-scala-js-8ced367e0d736b429f0b39ae7fde2b76b1d64ed5.tar.gz
hands-on-scala-js-8ced367e0d736b429f0b39ae7fde2b76b1d64ed5.tar.bz2
hands-on-scala-js-8ced367e0d736b429f0b39ae7fde2b76b1d64ed5.zip
More refactoring
Diffstat (limited to 'book/src/main/scalatex/book/handson/WebPage.scalatex')
-rw-r--r--book/src/main/scalatex/book/handson/WebPage.scalatex38
1 files changed, 19 insertions, 19 deletions
diff --git a/book/src/main/scalatex/book/handson/WebPage.scalatex b/book/src/main/scalatex/book/handson/WebPage.scalatex
index c3f66a4..5415ec7 100644
--- a/book/src/main/scalatex/book/handson/WebPage.scalatex
+++ b/book/src/main/scalatex/book/handson/WebPage.scalatex
@@ -41,7 +41,7 @@
@p
With that, the above snippet of code re-written using Scalatags looks as follows:
- @div(cls:="pure-g")
+ @div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
@hl.ref("examples/demos/src/main/scala/webpage/HelloWorld1.scala")
@@ -56,7 +56,7 @@
The Scalatags github page has @a("comprehensive documentation", href:="https://github.com/lihaoyi/scalatags#hello-world") on how to express all manner of HTML fragments using Scalatags, so anyone who's familiar with how HTML works can quickly get up to speed. Instead of a detailed listing, we'll walk through some interactive examples to show Scalatags in action!
@sect{User Input}
- @div(cls:="pure-g")
+ @div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
@hl.ref("examples/demos/src/main/scala/webpage/Inputs.scala", "val box")
@@ -76,7 +76,7 @@
@p
To begin with, let's define our list of items: Fruits!
-
+
@hl.ref("examples/demos/src/main/scala/webpage/Search0.scala", "val listings", "def")
@p
@@ -90,7 +90,7 @@
@p
Lastly, we just need to define the input box and output-container (as we did earlier), set the @hl.scala{onkeyup} event handler, and place it in a larger fragment, and then into our target:
- @div(cls:="pure-g")
+ @div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
@hl.ref("examples/demos/src/main/scala/webpage/Search0.scala", "val output")
@@ -101,7 +101,7 @@
@p
And there you have it! A working search box. This is a relatively self-contained example: all the items its searching are available locally, no Ajax calls, and there's no fancy handling of the searched items. If we want to, for example, highlght the matched section of each fruit's name, we can modify the @hl.scala{def renderListings} call to do so:
- @div(cls:="pure-g")
+ @div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
@hl.ref("examples/demos/src/main/scala/webpage/Search1.scala", "def renderListings", "lazy val")
@@ -134,7 +134,7 @@
One half of the web application faces forwards towards the user, managing and rendering HTML or Canvas for the user to view and interact with. Another half faces backwards, talking to various web-services or databases which turn the application from a standalone-widget into part of a greater whole. We've already seen how to make the front half, let's now talk about working with the back half.
@sect{Raw Javascript}
- @div(cls:="pure-g")
+ @div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
@hl.ref("examples/demos/src/main/scala/webpage/Weather0.scala", "val xhr")
@@ -142,12 +142,12 @@
@div(id:="div6")
@script("Weather0().main(document.getElementById('div6'))")
@p
- The above snippet of code uses the raw Javascript Ajax API in order to make a request to @a("openweathermap.org", href:="http://openweathermap.org/"), to get the weather data for the city of Singapore as a JSON blob. The part of the API that we'll be using is documented @a("here", href:="http://openweathermap.org/current"). For now, we're unceremoniously dumping it in a @hl.scala{pre} so you can see the raw response data.
+ The above snippet of code uses the raw Javascript Ajax API in order to make a request to @a("openweathermap.org", href:="http://openweathermap.org/"), to get the weather data for the city of Singapore as a JSON blob. The part of the API that we'll be using is documented @a("here", href:="http://openweathermap.org/current"). For now, we're unceremoniously dumping it in a @hl.scala{pre} so you can see the raw response data.
@p
As you can see, using the raw Javascript API to make the Ajax call looks almost identical to actually doing this in Javascript, shown below:
- @div(cls:="pure-g")
+ @div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
@hl.ref("examples/demos/src/main/resources/webpage/weather.js", "var xhr")
@@ -160,32 +160,32 @@
The primary syntactic differences are:
@ul
- @li
+ @li
@hl.scala{val}s for immutable data v.s. mutable @hl.javascript{var}s.
@li
@hl.scala("=>") v.s. @hl.javascript{function} to define the callback.
@li
- Scalatags' @hl.scala{pre} v.s. @hl.javascript{document.createElement}
+ Scalatags' @hl.scala{pre} v.s. @hl.javascript{document.createElement}
@p
Overall, they're pretty close, which is a common theme in Scala.js: using Javascript APIs in Scala.js is often as seamless and easy as using them in Javascript itself, and it often looks almost identical.
@sect{dom.extensions}
@p
- Although the Javascript XMLHttpRequest API is workable, it's kind of awkward and clunky compared to what you're used to in Scala. We create a half-baked object, set some magic properties, and call a magic function, which all has to be done in the correct order or it won't work.
+ Although the Javascript XMLHttpRequest API is workable, it's kind of awkward and clunky compared to what you're used to in Scala. We create a half-baked object, set some magic properties, and call a magic function, which all has to be done in the correct order or it won't work.
@p
With Scala.js, we provide a simpler API that is more clearly functional. First, you need to import some things into scope:
@hl.ref("examples/demos/src/main/scala/webpage/Weather1.scala", "import dom", "val url =")
-
+
@p
The first import brings in Scala adapters to several DOM APIs, which allow you to use them more idiomatically from Scala. The second brings in an implicit @hl.scala{ExecutionContext} that we'll need to run our asynchronous operations.
@p
Then we need the code itself:
- @div(cls:="pure-g")
+ @div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
@hl.ref("examples/demos/src/main/scala/webpage/Weather1.scala", "val url")
@@ -203,7 +203,7 @@
@p
First, let's make the call prettyprint the document, so at least we can see what it contains:
- @div(cls:="pure-g")
+ @div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
@hl.ref("examples/demos/src/main/scala/webpage/Weather2.scala", "Ajax.get")
@@ -217,7 +217,7 @@
@p
Now that we've pretty-printed it, we can immediately see what data it contains and which part of the data we want. Let's change the previous example's @hl.scala{onSuccess} call to extract the @hl.scala{weather}, @hl.scala{temp} and @hl.scala{humidity} and put them in a nice, human-friendly format for us to enjoy:
- @div(cls:="pure-g")
+ @div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
@hl.ref("examples/demos/src/main/scala/webpage/Weather3.scala", "Ajax.get")
@@ -226,7 +226,7 @@
@script("Weather3().main(document.getElementById('div10'))")
@p
- First we parse the incoming response, extract a bunch of values from it, and then stick it in a Scalatags fragment for us to see. Note how we can use the names of the attributes e.g. @hl.scala{json.name} even though @hl.scala{name} is a dynamic property which you can't be sure exists: this is because @hl.scala{json} is of type @hl.scala{js.Dynamic}, which allows us to refer to arbitrary parameters and methods on the underlying object without type-checking.
+ First we parse the incoming response, extract a bunch of values from it, and then stick it in a Scalatags fragment for us to see. Note how we can use the names of the attributes e.g. @hl.scala{json.name} even though @hl.scala{name} is a dynamic property which you can't be sure exists: this is because @hl.scala{json} is of type @hl.scala{js.Dynamic}, which allows us to refer to arbitrary parameters and methods on the underlying object without type-checking.
@p
Calls on @hl.scala{js.Dynamic} resolve directly to javascript property/method references, and will fail at run-time with an exception if used wrongly. This is also why we need to call @hl.scala{.toString} or @hl.scala{.asInstanceOf}on the values before use: without these casts, the compiler can't be sure what kind of value is underneath the @hl.scala{js.Dynamic} type, and so we have to provide it the guarantee that it is what it needs.
@@ -254,12 +254,12 @@
Here is the meat and potatoes of this program: every time it gets called with an array of weather-data, we iterate over the cities in that array. It then does a similar sort of data-extraction that we did earlier, putting the results into the @hl.scala{output} div we defined above, including highlighting.
@div(id:="div11")
- @script("WeatherSearch().main(document.getElementById('div11'))")
+ @script("WeatherSearch().main(document.getElementById('div11'))")
@p
And that's the working example! Try searching for cities like "Singapore" or "New York" or "San Francisco" and watch as the search narrows as you enter more characters into the text box. Note that the OpenWeatherMap API limits ambiguous searches to about a dozen results, so if a city doesn't turn up in a partial-search, try entering more characters to narrow it down.
-@sect{Interactive Web Pages Recap}
+@sect{Interactive Web Pages Recap}
@p
In this chapter, we've explored the basics of how you can use Scala.js to build interactive web pages. The two main contributions are using Scalatags to render HTML in a concise, safe way, and making Ajax calls to external web services. We combined these two capabilities in a small weather-search app that let a user interactively search for the weather in different cities around the world.
@p
@@ -272,6 +272,6 @@
Using @hl.scala{new dom.XMLHttpRequest} to make web requests feels just like the Javascript code to do so
@li
Using @hl.scala{Ajax.get(...)} and working with the resultant : @hl.scala{Future} feels a lot cleaner than directly using the Javascript API
-
+
@p
You're at this point reasonably pro