Skip to content

Instantly share code, notes, and snippets.

@vaclavsvejcar
Created October 7, 2016 11:19
Show Gist options
  • Save vaclavsvejcar/05e3190ec91f3e02ba9031b765181475 to your computer and use it in GitHub Desktop.
Save vaclavsvejcar/05e3190ec91f3e02ba9031b765181475 to your computer and use it in GitHub Desktop.
Scalatags ↔ Scala.Rx integration
import org.scalajs.dom.html.Span
import org.scalajs.dom.{Element, Node}
import rx._
import scala.annotation.tailrec
import scala.util.{Failure, Success}
import scalatags.JsDom.all._
/**
* Provides support for using [[https://github.com/lihaoyi/scala.rx Scala.Rx]] together with the
* [[https://github.com/lihaoyi/scalatags Scalatags]] library. This version has been tested with
* ''Scala.Rx'' 0.3.0 and ''Scalatags'' 0.6.0.
*
* @author Vaclav Svejcar (v.svejcar@norcane.cz)
*/
object rxinterop {
/**
* Sticks some Rx into a Scalatags fragment, which means hooking up an Obs
* to propagate changes into the DOM.
*/
implicit def RxFrag[T](rxValue: Rx[T])(implicit f: T => Frag, ctx: Ctx.Owner): Frag = {
@tailrec def clearChildren(node: org.scalajs.dom.Node): Unit = {
if (node.firstChild != null) {
node.removeChild(node.firstChild)
clearChildren(node)
}
}
def fSafe: Frag = rxValue match {
case r: Rx.Dynamic[T] => r.toTry match {
case Success(v) => v.render
case Failure(e) => span(e.getMessage, backgroundColor := "red").render
}
case v: Var[T] => v.now.render
}
var last: Node = fSafe.render
val container: Span = span(cls := "_rx")(last).render
rxValue.triggerLater {
val newLast = fSafe.render
//Rx[Seq[T]] can generate multiple children per propagate, so use clearChildren instead of replaceChild
clearChildren(container)
container.appendChild(newLast)
last = newLast
}
bindNode(container)
}
implicit def RxAttrValue[T: AttrValue](implicit ctx: Ctx.Owner) = new AttrValue[Rx.Dynamic[T]] {
def apply(t: Element, a: Attr, r: Rx.Dynamic[T]): Unit = {
r.trigger {
implicitly[AttrValue[T]].apply(t, a, r.now)
}
}
}
implicit def RxStyleValue[T: StyleValue](implicit ctx: Ctx.Owner) = new StyleValue[Rx.Dynamic[T]] {
def apply(t: Element, s: Style, r: Rx.Dynamic[T]): Unit = {
r.trigger {
implicitly[StyleValue[T]].apply(t, s, r.now)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment