scala.js — getting complex objects from JavaScript

怎甘沉沦 提交于 2019-12-04 06:49:57

Your attempt #4 is close, but not quite there. What you want is not a Scala.js-defined JS class. You want an actual facade trait. Then you can "pimp" its conversion to your Scala class in its companion object. You must also be careful to always use js.UndefOr for optional fields.

@ScalaJSDefined
trait JSMegaObject extends js.Object {
  val someInt: js.UndefOr[Int]
  val someStr: js.UndefOr[String],
  val someArray: js.UndefOr[js.Array[JSItem]],
  val someMap: js.UndefOr[js.Dictionary[JSItem]]
}

object JSMegaObject {
  implicit class JSMegaObjectOps(val self: JSMegaObject) extends AnyVal {
    def toMegaObject: MegaObject = {
      MegaObject(
          self.someInt.toOption,
          self.someStr.toOption,
          self.someArray.toOption.map(_.map(_.toItem)),
          self.someMap.toOption.map(_.mapValues(_.toItem)))
    }
  }
}

@ScalaJSDefined
trait JSItem extends js.Object {
  val name: js.UndefOr[String]
  val price: js.UndefOr[Int]
}

object JSItem {
  implicit class JSItemOps(val self: JSItem) extends AnyVal {
    def toItem: Item = {
      Item(
          self.name.toOption,
          self.price.toOption)
    }
  }
}

Getting these objects from JavaScript to Scala is actually fairly easy. You were on the right track, but needed a little bit more -- the trick is that, for cases like this, you need to use js.UndefOr[T] instead of Option[T], and define it as a facade. UndefOr is a Scala.js type that means exactly "this is either a T or undefined", and is mainly intended for interaction cases like this. It includes a .toOption method, so it's easy to interface with Scala code. You can then simply cast the object you get from JavaScript to this facade type, and everything ought to work.

Creating one of these JSMegaObjects from Scala takes a bit more work. For cases like this, where you are trying to create a complex structure with lots of fields that might or might not exist, we have JSOptionBuilder. It's named like that because it was written for the big "options" objects that are common in jQuery, but it's not jQuery-specific. You can find it in the jsext library, and documentation can be found on the front page there.

You can also see a moderately complex fully-worked example in the JQueryAjaxSettings class in jquery-facade. That shows both the JQueryAjaxSettings trait (the facade for the JavaScript object) and the JQueryAjaxSettingsBuilder (which lets you construct one from scratch in Scala).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!