2

My issue is also here: https://gist.github.com/somanythings/8c3d34de754af311d7826ea837d160b4

In using scalajs with japgolly's scalajs-react (https://github.com/japgolly/scalajs-react) library. I am trying to wrap the griddle grid http://griddlegriddle.github.io/Griddle/customization.html I want a custom column, and to do that requires I pass a columnMetadata structure which includes a component.

When I do, I can render a scalajs defined component that doesn't have properties, but if I try to access properties through renderP, or scope through renderS, they are both undefined in the scope of the render function. If I debug in the browser, they names are bound, and do have the expected values.

When I break on

def renderP(f: (DuringCallbackU[P, S, B], P) => ReactElement): Out =
  render($ => f($, $.props))

then $.props is undefined

What am I missing? Is it a simple typing issue in the ReactComponentB dispatching. Is it somehow related to https://github.com/japgolly/scalajs-react/issues/157, and I just haven't seen how?

// Confusion over how to pass a scalajs defined component to a javascript defined component

object GriddleComponentWrapper {
  // for customComponent I've tried js.Any, ReactComponentU 
  @ScalaJSDefined
  class ColumnMeta(val columnName: String, val order: Int, val customComponent: ReactClass=null) extends js.Object
}

case class GriddleComponentWrapper(results: js.Any, //Seq[Map[String, Any]],
                                   columns: Seq[String],
                                   columnMeta: Option[Seq[ColumnMeta]] = None,
                                   showSettings: Boolean = true,
                                   showFilter: Boolean = true
                                  ) {
  def toJS = {
    val p = js.Dynamic.literal()
    p.updateDynamic("results")(results)
    p.updateDynamic("columns")(columns)
    p.updateDynamic("showSettings")(showSettings)
    p.updateDynamic("showFilter")(showFilter)

    (columnMeta).foreach { case cm => p.updateDynamic("columnMetadata")(cm.toJsArray) }

    p
  }

  def apply(children: ReactNode*) = {
    val f = React.asInstanceOf[js.Dynamic].createFactory(js.Dynamic.global.Bundle.griddle) // access real js component , make sure you wrap with createFactory (this is needed from 0.13 onwards)
    f(toJS, children.toJsArray).asInstanceOf[ReactComponentU_]
  }

}

object MyTestGrid {

  @js.native
  class ColumnMetaProps(val data: js.Object, val rowData: js.Object, val metadata: js.Object) extends js.Object

  // I've tried making the Props argument js.Dynamic, and also the ColumnMetaProps above
  @JSExport
  val testComp = ReactComponentB[js.Dynamic]("Mine").renderP(
    (sc, props: js.Dynamic) => {
      //when debugging this in the browser, 'sc' and 'props' have inspectable object values with the expected members in the browser 
      //dev tools, BUT, they're undefined 
      log.info(s"what is ${sc.props}")
      log.info(s"what is $props")
      val string: Frag = if (!js.isUndefined(props)) props.data.toString() else "nothing!"
      <.h1(string)
    }).build

   @JSExport 
   val aCompletelyStaticComponentWithNoPropsWillWork = ReactComponentB[js.Dynamic]("MyStaticComponent").renderP(
    (sc, props: js.Dynamic) =>  <.h1("this renders!!") ).build


// am I passing the right thing to columnmeta with testComp.reactClass? 
 val columnMeta = (new ColumnMeta("c1", 1, testComp.reactClass) :: Nil).toJsArray

  val results = Seq(
    js.Dynamic.literal("c1" -> "row1c1", "c2" -> "row1c2"),
    ).toJsArray

  val component = ReactComponentB[js.Dynamic]("MyTestGrid")
    .render_P {
      props =>
        GriddleComponentWrapper(results, columns = "c1" :: "c2" :: Nil, columnMeta = Some(columnMeta))()
    }.build

  def apply() = component
}
lbp
  • 113
  • 1
  • 7
  • Not a fix in the vein of my question, but a workaround, so I'm commenting rather than 'answering', in the hope it helps someone else. I define my custom component thus: `val myCustomComp: js.Function = (props: ColumnMetaProps) => { log.info(s"here i can see ${props.data.toString()}") <.h1(s"some wrapper ${props.data.toString()}").render }` And then pass myCustomComp to columnMetadata – lbp Sep 29 '16 at 08:23
  • I was asking the same question on gitter : https://gitter.im/japgolly/scalajs-react?at=57fdda6bdfe82a365b1a71ad – jhegedus Oct 12 '16 at 07:13
  • where do you pass here a scalajs component to a js component ? https://gist.github.com/somanythings/8c3d34de754af311d7826ea837d160b4 ? all i can see here is scalajs code... you mean here https://gist.github.com/somanythings/8c3d34de754af311d7826ea837d160b4#file-scalajsreactinterop-scala-L57 ? – jhegedus Oct 12 '16 at 08:11
  • @jhegedus griddle is a js react component. My griddle wrapper is a scalajs proxy to that. – lbp Oct 13 '16 at 13:25

1 Answers1

4

React.JS requires that props and state always be an object (or null). Using a single Scala value like a primitive or case class instance, causes exceptions in React.JS. Therefore in scalajs-react, in order to allow users to use any props/state types in a type-safe manner, under the hood an object with a single key of "v" is used. I.e. instead of using 123 directly, {v:123} is used.

You likely will need to accommodate that boxing in your code.

Now, in the next major version (see the "neo" branch), the representations of components vastly improved such that there is no more hidden magic like I just described. Whereas v0.x wasn't designed to facilitate JS↔Scala component interop, it will be explicit, obvious, and hopefully trivial in neo.

Golly
  • 1,319
  • 8
  • 18
  • What does this mean in practice ? Is there a simple example how can I do that ? – jhegedus Oct 12 '16 at 07:17
  • I don't personally know of an example but I suggest asking in the scalajs-react gitter chat room. I think one or two people there had a similar use case. Also if you find or create an example, please consider contributing it to scalajs-react's docs to help others with the same question in the future. Good luck. – Golly Oct 12 '16 at 23:48
  • Hi, thanks for the tip, I did just that, and got help, I documented the solution here : https://github.com/jhegedus42/scalajs-react-playaround/wiki/ReactJS-----ScalaJS-React-Interop – jhegedus Oct 13 '16 at 06:36