Techniques

Techniques strongly tied to OAT.

Shorter stuff can go here. Longer or more important stuff may get their own page.

Delivering data to the browser

When a web page has dynamic data to display, there are several general approaches:

  1. Render it all on the server. Ask the server for an updated page when anything changes (Web1.0).

  2. Deliver an HTML shell of the page and some ScalaJS. Fetch the data needed from a web service and render it on the browser.

  3. Embed the data in the HTML. Use ScalaJS to extract it and render the page.

  4. Render as much on the server as you can.

Approaches 2, 3, and 4 assume you have ScalaJS/Javascript running to add interactivity in addition to (possibly) rendering the page.

I (Byron) had assumed/thought for quite a while that #2 was the preferred way to go. We have lots of #3 thanks to some coop students, but I was suspicious. A chat with Claude.ai in 2025 suggests real advantages (faster load/render) for #3 over #2. It also said that the current best practise was #4. Render as much as you can on the server, adding Javascript for interactivity and possibly rerendering the page with newly fetched data. However, I don’t see enough advantage to move in that direction.

Digging into #3… In the views delivered by the wapp controller, look for withData. For example, in oat.wapp.views.forms.FormsSubmittedView we have

    Template("Submitted Forms")
      .withJS(npm.sortable)
      .withData(
        "formDefinition"    -> Json.toJson(form),
        "submissions"       -> Json.toJson(submissions),
        "hasFormsAdminPerm" -> JsBoolean(context.hasPermission(Permission.Forms))
      )
      .render

This embeds the form submission data in the HTML for retrieval on the browser.
In the browser’s version of this class, we have

  private val model = SubmittedModel(
    context[Userid]("userid"),
    context[Form]("formDefinition"),
    context[Vector[Submission]]("submissions"),
    context[Boolean]("hasFormsAdminPerm")
  )

The userid was added automatically by the template along with name, whether this is the production instance, a csrf token, and if the user has an instructor or advisor role. The context function extracts the data with the given name and converts it to the specified type.