|
| 1 | +# bindable.scala |
| 2 | +[](https://index.scala-lang.org/thoughtworksinc/bindable.scala/bindable) |
| 3 | +[](https://javadoc.io/page/com.thoughtworks.binding/bindable_sjs0.6_2.12/latest/com/thoughtworks/binding/bindable/index.html) |
| 4 | +[](https://travis-ci.org/ThoughtWorksInc/bindable.scala) |
| 5 | + |
| 6 | +**bindable.scala** is a library of type classes for creating user-friendly [Binding.scala](https://github.com/ThoughtWorksInc/Binding.scala) components. |
| 7 | + |
| 8 | +## Motivation |
| 9 | + |
| 10 | +When creating a component that accepts parameters or “holes”, it is difficult to determine the types of those parameters. |
| 11 | + |
| 12 | +For example, the following component accepts two `Binding` as parameters: |
| 13 | + |
| 14 | +```scala |
| 15 | +@dom def myComponent1(title: Binding[String], children: Binding[BindingSeq[Node]]) = { |
| 16 | + <div title={title.bind}> |
| 17 | + {children.bind} |
| 18 | + </div> |
| 19 | +} |
| 20 | +``` |
| 21 | + |
| 22 | +By typing parameters as `Binding`s, `myComponent1` allows partial rendering whenever the value of `title` or `children` is changed. Unfortunately, it is too verbose to use `myComponent1` for simple use cases when the parameters are constants. |
| 23 | + |
| 24 | +```scala |
| 25 | +// Does not compile |
| 26 | +@dom def myUseCases1 = myComponent1("My Title", <img/>).bind |
| 27 | + |
| 28 | +// Compiles, but too verbose |
| 29 | +@dom def myUseCases2 = myComponent1(Constant("My Title"), Constant(Constants(<img/>))).bind |
| 30 | +``` |
| 31 | + |
| 32 | +In this library, we introduced two type classes, `Bindable` and `BindableSeq`, to allow heterogeneous types of parameters for a component. |
| 33 | + |
| 34 | +## Usage |
| 35 | + |
| 36 | +### Step 1: adding the following settings into your `build.sbt` |
| 37 | + |
| 38 | +```sbt |
| 39 | +addCompilerPlugin("org.spire-math" %% "kind-projector" % "latest.release") |
| 40 | + |
| 41 | +libraryDependencies += "com.thoughtworks.binding" %%% "bindable" % "latest.release" |
| 42 | +``` |
| 43 | + |
| 44 | +### Step 2: creating a component that accepts bindable parameters |
| 45 | + |
| 46 | +```scala |
| 47 | +import com.thoughtworks.binding.bindable._ |
| 48 | +import org.scalajs.dom.raw._ |
| 49 | +@dom def myComponent2[Title: Bindable.Lt[?, String], Children: BindableSeq.Lt[?, Node]](title: Title, children: Children) = { |
| 50 | + <div title={title.bind}> |
| 51 | + {children.bindSeq} |
| 52 | + </div> |
| 53 | +} |
| 54 | +``` |
| 55 | + |
| 56 | +### Step 3: using the component with any parameters that can be converted to `Binding` or `BindingSeq` |
| 57 | + |
| 58 | + |
| 59 | +```scala |
| 60 | +import com.thoughtworks.binding._, Binding._ |
| 61 | +@dom def myUseCases3 = myComponent2("My Title", <img/>).bind |
| 62 | +@dom def myUseCases4 = myComponent2(Constant("My Title"), Constant(Constants(<img/>))).bind |
| 63 | +@dom def myUseCases5 = myComponent2("My Title", <img/><img/>).bind |
| 64 | +@dom def myUseCases6 = myComponent2("My Title", Binding(<img/><img/>)).bind |
| 65 | +``` |
| 66 | + |
| 67 | +Unlike use cases of `myComponent1`, all the above use cases of `myComponent2` compile now, with the help of the `Bindable` and `BindableSeq` type classes. |
| 68 | + |
| 69 | +## Links |
| 70 | + |
| 71 | +* [Documentation](https://javadoc.io/page/com.thoughtworks.binding/bindable_sjs0.6_2.12/latest/com/thoughtworks/binding/bindable/index.html) |
| 72 | +* [Binding.scala](https://github.com/ThoughtWorksInc/Binding.scala) |
| 73 | +* [Limitations of the component model](https://github.com/ThoughtWorksInc/Binding.scala/issues/128) |
0 commit comments