Tyrian, an Elm inspired frontend framework for Scala.js.

Subscriptions

A notification of change

Subscriptions (Subs) are used to observe something that changes over time, and to emit discrete messages when something happens.

For example, we could chose to observe the mouse position, and emit a message every time the mouse moves, like this:

import org.scalajs.dom.document
import org.scalajs.dom.MouseEvent
import cats.effect.IO

import tyrian.*

type Model = Int

enum Msg:
  case MouseMove(x: Double, y: Double)

val mousePosition: Sub[IO, Msg] = 
  Sub.fromEvent("mousemove", document) { case e: MouseEvent  =>
    Option(Msg.MouseMove(e.pageX, e.pageY))
  }

def subscriptions(model: Model): Sub[IO, Msg] =
  mousePosition

A change in mouse position will now result in a MouseMove message that will be piped back to your updateModel function.

Subscriptions can be used on their own, or in conjunction with commands to form a pub/sub relationship with a resource, as is the case with web sockets and the tyrian-indigo bridge.

Working with Subscriptions

Subscriptions are Functors which means that you can map over them to change the resultant message. They are also Monoids which means that they have an empty representation Sub.None and that you can combine them together, using combine or the shorthand operator: sub1 |+| sub2.

A common thing to need to do is batch multiple subs together into a single subscription, like this:

import scala.concurrent.duration._

import org.scalajs.dom.document
import org.scalajs.dom.MouseEvent

import tyrian.*

enum Msg:
  case MouseMove(x: Double, y: Double)
  case CurrentSeconds(seconds: Double)

val mousePosition: Sub[IO, Msg] = 
  Sub.fromEvent("mousemove", document) { case e: MouseEvent  =>
    Option(Msg.MouseMove(e.pageX, e.pageY))
  }

val tick =
  Sub.every[IO](1.second, "tick")
    .map(date => Msg.CurrentSeconds(date.getSeconds()))

def subscriptions(model: Model): Sub[IO, Msg] =
  Sub.Batch[IO, Msg](
    mousePosition,
    tick
  )