scala.jsudash

Scala.js: How do I read the value using of an input element using Scala.js?


I am trying to do something like this:

<input id="test">Hello!</input>

import io.udash.wrappers.jquery.jQ

// Read from Scala
val x = jQ("#test").value().asIntanceOf[String]

But, I get a ClassCastException saying String | Int | Double | js.Array[Any] cannot be cast to a String


Solution

  • I came up with a typeclass approach (which hides the ugly asInstanceOf):

    import scala.scalajs.js.|
    import scala.util.Try
    
    trait JsRead[A] { self =>
      import JsRead.Or
      def apply(value: Or): Option[A]
    
      def map[B](f: A => Option[B]): JsRead[B] = new JsRead[B] {
        override def apply(value: Or) = self.apply(value).flatMap(f)
      }
    }
    
    object JsRead {
      type Or = _ | _
    
      def apply[A](f: Or => Option[A]): JsRead[A] = new JsRead[A] {
        override def apply(value: Or) = f(value)
      }
    
      implicit class Dsl(value: Or) {
        def as[A](implicit reader: JsRead[A]): Option[A] =
          reader(value)
      }
    
      implicit val string: JsRead[String] = JsRead(x => Try(x.asInstanceOf[String]).toOption)
      implicit val int: JsRead[Int]       = string.map(_.toIntOption)
      implicit val double: JsRead[Double] = string.map(_.toDoubleOption)
    }
    

    Now I can use it as:

    import io.udash.wrappers.jquery.{jQ => $}
    
    for {
      deposit           <- $("#deposit").value().as[Int]
      monthlyWithdrawal <- $("#monthlyWithdrawal").value().as[Int]
      irr               <- $("#irr").value().as[Double]
      inflation         <- $("#inflation").value().as[Double]
      year              <- $("#year").value().as[Int]
    } {
      // do something
    }