OlivierBlanvillain / monadic-html

Tiny DOM binding library for Scala.js
https://olivierblanvillain.github.io/monadic-html/examples/
MIT License
225 stars 24 forks source link

Is there anything like 'Rx[Action]' ? #106

Closed sometao closed 6 years ago

sometao commented 6 years ago

Use case:

Some action (or operation) needs binding to a Var(state). When the state changes, the action should be executed.

My solution is:

import mhtml._
import org.scalajs.dom
import org.scalajs.dom.raw.{Element, HTMLElement, MouseEvent}
import scala.scalajs.js.Date
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import scala.xml.Node

@JSExportTopLevel("front.Main")
object Main {
  @JSExport
  def test12(): Unit = {
    val state = Var(100)
    var targetOp: Option[HTMLElement] = None

    val actionRx= state.map{ state =>
      targetOp.foreach{ target =>
        target.style.width = state.toString + "px"
      }
      ""
    }

    val body =
      <div>
        <h1>Hello.</h1>
        <button onclick={() => state.update( s => s + 10) }>+</button>
        <button onclick={() => state.update( s => s - 10) }>-</button>
        <div style="display:flex; height:200px">
          <div style="width:100px; background:red"></div>
          <div style="width:100px; background:yellow"></div>
          <div mhtml-onmount={e: HTMLElement => targetOp = Some(e) } style="width:100px; background:blue"></div>
        </div>
        {actionRx}
      </div>
    mount(dom.document.body, body)
  }
}

Is there any better solution?

OlivierBlanvillain commented 6 years ago

Something like this should work:

val state = Var(100)
val body =
  <div>
    <h1>Hello.</h1>
    <button onclick={ () => state.update( s => s + 10) }>+</button>
    <button onclick={ () => state.update( s => s - 10) }>-</button>
    <div style="display:flex; height:200px">
      <div style={ state.map(s => s"width:${s}px; background:red") }></div>
      <div style={ state.map(s => s"width:${s}px; background:yellow") }></div>
      <div style={ state.map(s => s"width:${s}px; background:blue") }></div>
    </div>
  </div>
OlivierBlanvillain commented 6 years ago

If you need to attach side effects to a Var it's best to call .impure.run on it (and manually manage the cancellation than run returns). Going thought map feels a bit like a hack :)

sometao commented 6 years ago

Side effects are what I need. I will use .impure.run and handle the cancellation. Thank you.