Tuesday 3 September 2013

Building an assessment app in two days -- 4th commit.

The fourth commit has been pushed to GitHub.

Starting to set up the client

This sets up the beginnings of the Angular.js / Play app. Though the app doesn't do anything yet.

A quick run-down on its contents:

  • Global.scala

    This contains the application start-up code for Play. At the moment, it has three things to set up:

    • Set up the database, looking in application.conf for connection details (which in turn looks up some environment variables)

    • Set the home action for DataAction

      DataAction is particularly designed for "single page apps" such as this one.

      When the app is running in the client, Angular.js is going to request data in JSON format from the server, and render it appropriately in HTML.

      But at any stage, the user might click "Refresh", in which case the browser will make a request to the server on that URL. And in that case, we don't want to return JSON data, but the HTML and Javascript that will bootstrap our Angular.js app.

      DataAction uses the Accepts HTTP header to tell the difference between a request from our Angular.js app, and a request from a browser asking for HTML.

      If a request is made with an Accepts header looking for a JSON response, then the DataAction will run and return (asynchronously) data in JSON format. But if the request is made with an Accepts header asking for HTML, then it returns the home action (delivering our Angular.js app to the browser to get started).

    • Set the look up method for RefById and RefManyById.

      This configures how items are retrieved from the database. The basic handy library, (where Ref, RefById, LazyId, and RefManyById, amongst others, are defined) is database agnostic, so this is how we wire it up to our ReactiveMongo database layer.

      The DAO classes we have defined automatically inherit partial functions for looking up the classes they handle. (The DAO trait in handy-reactivemongo defines an appropriate partial function). So, the lookup method just has to call the partial functions from the DAO classes to see which one applies.

      (If you're new to Scala, a "partial function" is essentially a function that can say "actually, no I can't handle that argument after all". So, we can keep a set of partial functions for looking up different classes of item by their ID, and the partial functions themselves can decide whether or not they apply to the reference we gave them.)

  • Application.scala

    This contains a few key "actions" for our app.

    • index

      This action delivers the HTML for our Angular.js app

    • The default action

      Angular.js includes its own routing (its own handling of URLs) in the browser. In a single page app, the routing on the client side is somewhat decoupled from the routing on the server side.

      This means it's perfectly possible that there will be a valid URL in the client that isn't defined as an explicit action on the server.

      But we still need to handle the request if the user hits "refresh" and causes their browser to make an HTTP GET request to the server for that URL.

      The default action causes those requests to return the index action (containing our Angular.js app).

    • The partials action

      Periodically, Angular.js needs to request the HTML for a new template to show. As we define new views, we will be defining new partial templates.

      If we gave each partial template its own entry in the routes file, then in development, every time we add a new partial template, Play would want to recompile all the controllers as the routes file (containing all the controllers' action URLs) would have changed. If we instead put all the partials into this one action, then adding a new partial template only causes the Application controller to recompile.

  • main.js

    We're going to use require.js to combine and minify our Javascript (because we're going to have a lot of small Javascript files by the time we're finished).

    At the moment, there are no Javascript files to load, so we're "requiring" an empty array of files.

    We have set it up, though, so that when all the (zero) libraries have loaded, require should tell Angular.js to bootsrap.

  • includeDirectives.scala.html

    This is where we'll embed the HTML for Angular.js template directives. But at the moment, there aren't any.

No comments: