Live

io.eezo.live.Live
object Live

The live layer's front door: mount in a handler, routes on the server, the event binding attributes in views.

A handler embeds a component wherever it wants in its own page:

def board(request: Request): Response =
 Response.Ok(layout(Live.mount(request, Board())))

mount runs init, registers the page, and returns a fragment of two nodes: the anchor `

` holding the first render, and the `` that brings it to life. Carrying the script in the fragment is what lets http stay blind to live (design/live.md §2.3): it never scans a response for markers, because the mount is just a value in whatever the handler returns. A whole document goes out as written and content comes back inside the application's Layout; the script travels with the mount either way. The script's address is a plain string on purpose — the socket and the script are served unmounted under the reserved prefix, so a mounted page must not have them rewritten.

One mount per response in v1. A second mount renders (each is an ordinary value) but the client drives only the first anchor it finds; multi-mount is on the backlog.

The registry and the reaper are process-wide the way the installed Database is: built once, reached from the routes below, invisible to user code.

Attributes

Source
Live.scala
Graph
Supertypes
class Object
trait Matchable
class Any
Self type
Live.type

Members list

Value members

Concrete methods

def mount[S](request: Request, component: Component[S]): Html

Mounts component as a live page: the returned fragment goes wherever the handler's own layout puts it. At the registry's cap the component is rendered once, statically, and the page says so in an attribute the client logs — a busy site degrades to working pages that do not update, never to errors (design/live.md §2.5).

Mounts component as a live page: the returned fragment goes wherever the handler's own layout puts it. At the registry's cap the component is rendered once, statically, and the page says so in an attribute the client logs — a busy site degrades to working pages that do not update, never to errors (design/live.md §2.5).

request is the request being answered, and the one thing read off it is currentUser: a page rendered behind a guarded route is bound to that user and admits only their socket (docs/tutorials/a-live-page.md §7). There is no request free overload, because a page that forgot to say who rendered it would quietly stay unbound, and that has to be a compile error.

Attributes

Source
Live.scala
def mount[S](request: Request, create: Async[S] => Component[S]): Html

The factory overload for a component that calls out: the Async it is built with is the page's own, so work it declares comes back through this page's mailbox. Wired through a relay because the page cannot exist before its component does; the relay is aimed before init runs, so even a fetch-at-mount lands.

The factory overload for a component that calls out: the Async it is built with is the page's own, so work it declares comes back through this page's mailbox. Wired through a relay because the page cannot exist before its component does; the relay is aimed before init runs, so even a fetch-at-mount lands.

Attributes

Source
Live.scala
def onChange(name: String): Attr

A committed-change binding, sent at once: a checkbox or radio arrives as Map("value" -> "on" | ""), a select or text input as its value. The right binding for controls where every change is a decision rather than a keystroke.

A committed-change binding, sent at once: a checkbox or radio arrives as Map("value" -> "on" | ""), a select or text input as its value. The right binding for controls where every change is a decision rather than a keystroke.

Attributes

Source
Live.scala
def onClick(name: String): Attr

Marks an element as a click binding: button(Live.onClick("inc"), "+") sends Event("inc") to the component's handle. The client delegates one listener at the document, so the binding survives any patch that replaces the element — and so do all the bindings below.

Marks an element as a click binding: button(Live.onClick("inc"), "+") sends Event("inc") to the component's handle. The client delegates one listener at the document, so the binding survives any patch that replaces the element — and so do all the bindings below.

Attributes

Source
Live.scala
def onInput(name: String, debounceMillis: Int = ...): Seq[Attr]

A per-keystroke binding, debounced on the client: after debounceMillis of quiet the element's current value arrives as Event(name, Map("value" -> …)). The debounce is per element, so typing in one field does not flush another's timer.

A per-keystroke binding, debounced on the client: after debounceMillis of quiet the element's current value arrives as Event(name, Map("value" -> …)). The debounce is per element, so typing in one field does not flush another's timer.

Attributes

Source
Live.scala
def onSubmit(name: String): Attr

A form submission binding: the browser's submit is intercepted, and every named field in the form arrives as one payload, Map(fieldName -> value). Checkboxes follow the form convention: present as "on" when ticked, absent otherwise.

A form submission binding: the browser's submit is intercepted, and every named field in the form arrives as one payload, Map(fieldName -> value). Checkboxes follow the form convention: present as "on" when ticked, absent otherwise.

Attributes

Source
Live.scala
def routes(allowedOrigins: Set[String]): Seq[Route]

What io.eezo.http.HttpApp.frameworkRoutes carries when LiveApp is mixed in: the one socket every page joins, and the client script. Both under the reserved prefix, both unmounted, both absent from eezo routes (they are the framework's, not the user's) though present in the boot listing, which shows what is actually served.

What io.eezo.http.HttpApp.frameworkRoutes carries when LiveApp is mixed in: the one socket every page joins, and the client script. Both under the reserved prefix, both unmounted, both absent from eezo routes (they are the framework's, not the user's) though present in the boot listing, which shows what is actually served.

allowedOrigins is the one thing the socket needs from the application, which is why this is a method with no parameterless twin: a twin would let LiveApp drop an application's list without a compile error. Empty means a socket is admitted from the server's own origin only.

Attributes

Source
Live.scala

Concrete fields

val ignore: Attr

The opt-out for a subtree some other script owns (a chart, an embedded editor): eezo still patches the marked element's own attributes but never its children (design/live.md §1.1 on §4.6). The round-trip guarantee deliberately ends at this attribute.

The opt-out for a subtree some other script owns (a chart, an embedded editor): eezo still patches the marked element's own attributes but never its children (design/live.md §1.1 on §4.6). The round-trip guarantee deliberately ends at this attribute.

Attributes

Source
Live.scala