|
1 | 1 | # FormBinder
|
2 | 2 |
|
3 |
| -FormBinder is a tool to bind reactjs form fields to a DataModel plus validation. |
| 3 | +FormBinder is a tool to bind |
| 4 | +[scalajs-react](https://github.com/japgolly/scalajs-react) |
| 5 | +form fields to a data model plus validation. |
4 | 6 |
|
| 7 | +My main goal was to provide a data binding between form fields and |
| 8 | +data model and a way to specify extra validation rules without loosing |
| 9 | +flexibility of the form design. |
5 | 10 |
|
6 |
| -## Usage |
7 |
| - |
8 |
| -```scala |
9 |
| -import FormBinder.{ValidationResult, Validator} |
10 |
| - |
11 |
| - |
12 |
| -case class Data(username: String = "", |
13 |
| - password1: String = "", |
14 |
| - password2: String = "") |
15 |
| - |
16 |
| -// define validation rules in companion object |
17 |
| -// note: the field names must match to the data model |
18 |
| -object Data { |
19 |
| - |
20 |
| - def username(username: String) = { |
21 |
| - if (username.isEmpty) ValidationResult.withError("Please specify username") |
22 |
| - else ValidationResult.success |
23 |
| - } |
24 |
| - |
25 |
| - def password1(password1: String) = // simpler syntax |
26 |
| - Validator(password.isEmpty, "Please specify password") |
27 |
| - |
28 |
| - def password2(password1: String, password2: Option[String]) = { |
29 |
| - // you can "inject" any other fields as Options |
30 |
| - if (password1.isEmpty) ValidationResult.withError("Please specify password") |
31 |
| - else if (password2.nonEmpty && password1 != password2.get) ValidationResult.withError("Must match password.") |
32 |
| - else ValidationResult.success |
33 |
| - } |
34 |
| - |
35 |
| - // define global (not tied to a specific field) validation rules here |
36 |
| - def $global(data: Data) = { |
37 |
| - ValidationResult.success |
38 |
| - } |
39 |
| - |
40 |
| - |
41 |
| - ... |
| 11 | +## Installation |
42 | 12 |
|
43 |
| - // then define the form layout fields -- probably inside the component's Backend |
44 |
| - |
45 |
| - object FormDescription extends FormBinder.FormDescription[Data] { |
| 13 | +Currently it is available as a sonatype snapshot, add this to your build.sbt: |
46 | 14 |
|
47 |
| - // field names must match the data model's field names |
48 |
| - val username = FormFieldDescriptor((a: FormFieldArgs[String]) => |
49 |
| - MuiTextField( |
50 |
| - floatingLabelText = "Username", |
51 |
| - onChange = (e: ReactEventI) => a.onChangeHandler(e.target.value), |
52 |
| - errorText = a.currentValidationResult.errorMessage)() |
53 |
| - ) |
54 |
| - val password1 = ... |
55 |
| - val password2 = ... |
56 |
| - |
57 |
| - // define what to do after form data and/or form validation changes |
58 |
| - override def onChange(newData: Option[Data], |
59 |
| - allFieldValidationResults: List[ValidationResult], |
60 |
| - globalFormValidationResult: ValidationResult): Callback = { |
61 |
| - $.modState(_.copy(data = newData, globalValidationResult = globalFormValidationResult)) |
62 |
| - } |
63 |
| - } |
64 |
| - |
65 |
| - // this binds the data model, validation rules and form description together |
66 |
| - val form = FormBinder.bind[Data](FormDescription) |
| 15 | +``` |
| 16 | +libraryDependencies += "com.github.torstenrudolf.scalajs-react-form-binder" %%% "core" % "0.0.1-SNAPSHOT" |
| 17 | +``` |
67 | 18 |
|
68 |
| - // use it like this: |
69 |
| - val handleSubmit: Callback = $.state >>= { (state: State) => |
70 |
| - if (state.globalFormValidationResult.isValid) { |
71 |
| - // do something with state.data.get |
72 |
| - } else form.showUninitializedFieldErrors |
73 |
| - } |
74 |
| - |
75 |
| - def render(state: State) = <.div( |
76 |
| - <.form( |
77 |
| - ^.onSubmit --> handleSubmit, |
78 |
| - ^.display.flex, |
79 |
| - ^.flexDirection.column, |
80 |
| - loginForm.field(LoginFormDescription.username), |
81 |
| - loginForm.field(LoginFormDescription.password) |
82 |
| - ), |
83 |
| - if (!state.globalValidationResult.isValid) { |
84 |
| - <.div(state.globalValidationResult.errorMessage) |
85 |
| - } else "" |
86 |
| - ) |
| 19 | +You also might need to add the resolver for the sonatype snapshot repo: |
87 | 20 | ```
|
| 21 | +resolvers ++= Resolver.sonatypeRepo("snapshots") |
| 22 | +``` |
| 23 | + |
| 24 | +## Usage |
| 25 | +See demo: https://torstenrudolf.github.io/scalajs-react-form-binder |
88 | 26 |
|
| 27 | +* define the data model as a `case class` |
| 28 | +* optionally define validation rules in an object |
| 29 | +* define the form fields in a FormLayout object |
| 30 | +* the matching of the field-names is type-safe as it is done at compile time via a macro |
| 31 | +* have full control over display of the form fields inside your `render` method |
89 | 32 |
|
90 | 33 | ## TODO
|
91 | 34 |
|
92 |
| -* add prebuild FormFieldDescriptors for material-ui |
| 35 | +* add tests |
| 36 | +* add prebuild FormFieldDescriptors for material-ui fields |
0 commit comments