Custom Page

Create and use a Custom Page.

The example is based on DemoResultClient from scala-adapters. The Custom Page displays the incoming images at random positions and in random sizes.

Constraints

Shared Data

We can reuse /shared/src/main/scala/shared/GetStartedResult

Create HtmlElement

First we create the HTMLElement with for the image /client/src/main/scala/client/GetStartedClient.scala

case class ImageElem(getStartedResult: GetStartedResult) {

  @dom
  lazy val imageElement: Binding[HTMLElement] =
      <img style={randomImgStyle} src={getStartedResult.imgUrl}/>
  ...
}

randomImgStyle creates the random position and in random size of the image.

Extend the UIStore

We extend the UIStore with UIGetStartedStore

trait GetStartedUIStore
  extends UIStore {

  protected def getStartedUIState: GetStartedUIState

  // type class instance for ImageElem
  implicit object concreteResultForImageElem extends ConcreteResult[ImageElem] {

    override def fromJson(lastResult: JsValue): JsResult[ImageElem] =
      Json.fromJson[GetStartedResult](lastResult)
        .map(ImageElem)
  }

  // provide a function to update the ImageElems from the ConcreteResults
  def updateImageElems(lastResults: Seq[JsValue]): Seq[ImageElem] = {
    ToConcreteResults.toConcreteResults(getStartedUIState.imageElems, lastResults)
  }
}

The idea of a UIStore is, that changing the UIState is done just in one place.

Create the Client

case class GetStartedClient(context: String, websocketPath: String)
  extends AdaptersClient
    with GetStartedUIStore {

  // init the custom UIState
  val getStartedUIState = GetStartedUIState()

  // create the websocket
  private lazy val socket = ClientWebsocket(uiState, context)

  @dom
  protected def render: Binding[HTMLElement] = {
    socket.connectWS(Some(websocketPath))
    <div>
      {imageContainer.bind}
    </div>
  }

  @dom
  private def imageContainer = {
    val lastResults = uiState.lastResults.bind
    val imageElems = updateImageElems(lastResults)
    <div>
      {Constants(imageElems: _*)
      .map(_.imageElement.bind)}
    </div>
  }
}

This is more or less a composition of HTMLElements, done with Binding.scala.

Here is a small intro to Binding.scala binding-google-maps.

Update Client Application

We have to update our client slightly /client/src/main/scala/client/GetStartedClient.scala

      ...
      case CUSTOM_PAGE =>
        GetStartedClient(context, websocketPath).create()
      ...

As we have now our implementation for our CUSTOM_PAGE.

Check Result

Running the Project and running the Job, should give you this:

screenshot_custom_page