form_props 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +714 -0
- data/lib/form_props/action_view_extensions/form_helper.rb +120 -0
- data/lib/form_props/form_builder.rb +223 -0
- data/lib/form_props/form_options_helper.rb +158 -0
- data/lib/form_props/inputs/base.rb +164 -0
- data/lib/form_props/inputs/check_box.rb +69 -0
- data/lib/form_props/inputs/collection_check_boxes.rb +36 -0
- data/lib/form_props/inputs/collection_helpers.rb +53 -0
- data/lib/form_props/inputs/collection_radio_buttons.rb +35 -0
- data/lib/form_props/inputs/collection_select.rb +30 -0
- data/lib/form_props/inputs/color_field.rb +27 -0
- data/lib/form_props/inputs/date_field.rb +17 -0
- data/lib/form_props/inputs/datetime_field.rb +32 -0
- data/lib/form_props/inputs/datetime_local_field.rb +17 -0
- data/lib/form_props/inputs/email_field.rb +13 -0
- data/lib/form_props/inputs/file_field.rb +13 -0
- data/lib/form_props/inputs/grouped_collection_select.rb +31 -0
- data/lib/form_props/inputs/hidden_field.rb +16 -0
- data/lib/form_props/inputs/month_field.rb +17 -0
- data/lib/form_props/inputs/number_field.rb +21 -0
- data/lib/form_props/inputs/password_field.rb +18 -0
- data/lib/form_props/inputs/radio_button.rb +48 -0
- data/lib/form_props/inputs/range_field.rb +13 -0
- data/lib/form_props/inputs/search_field.rb +28 -0
- data/lib/form_props/inputs/select.rb +42 -0
- data/lib/form_props/inputs/submit.rb +26 -0
- data/lib/form_props/inputs/tel_field.rb +13 -0
- data/lib/form_props/inputs/text_area.rb +37 -0
- data/lib/form_props/inputs/text_field.rb +28 -0
- data/lib/form_props/inputs/time_field.rb +17 -0
- data/lib/form_props/inputs/time_zone_select.rb +22 -0
- data/lib/form_props/inputs/url_field.rb +13 -0
- data/lib/form_props/inputs/week_field.rb +17 -0
- data/lib/form_props/inputs/weekday_select.rb +28 -0
- data/lib/form_props/version.rb +5 -0
- data/lib/form_props.rb +45 -0
- metadata +120 -0
data/README.md
ADDED
@@ -0,0 +1,714 @@
|
|
1
|
+
# Form Props
|
2
|
+
|
3
|
+
FormProps is a Rails form builder that outputs input attributes (in JSON) instead of
|
4
|
+
tags. Now you can enjoy the conviences of Rails helpers in other view libraries like
|
5
|
+
React, and React Native.
|
6
|
+
|
7
|
+
By separting attributes from tags, FormProps can offer greater flexbility than normal
|
8
|
+
Rails form builders; allowing designers to stay longer in HTML land and more easily
|
9
|
+
customize their form structure without needing to know Rails.
|
10
|
+
|
11
|
+
## Caution
|
12
|
+
|
13
|
+
This project is in its early phases of development. Its interface, behavior,
|
14
|
+
and name are likely to change drastically before a major version release.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add to your `Gemfile`
|
19
|
+
|
20
|
+
```
|
21
|
+
gem "form_props"
|
22
|
+
```
|
23
|
+
|
24
|
+
and `bundle install`
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
`form_props` is designed to be used in a [PropsTemplate] template (it can work with
|
28
|
+
[jbuilder](#jbuilder)). For example in your `new.json.props`:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
json.some_form do
|
32
|
+
form_props(@post) do |f|
|
33
|
+
f.text :title
|
34
|
+
f.submit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
would output
|
40
|
+
|
41
|
+
```
|
42
|
+
{
|
43
|
+
someForm: {
|
44
|
+
props: {
|
45
|
+
id: "create-post",
|
46
|
+
action: "/posts/123",
|
47
|
+
accept-charset: "UTF-8",
|
48
|
+
method: "post"
|
49
|
+
},
|
50
|
+
extras: {
|
51
|
+
method: {
|
52
|
+
name: "_method",
|
53
|
+
type: "hidden",
|
54
|
+
defaultValue: "patch",
|
55
|
+
autocomplete: "off"
|
56
|
+
},
|
57
|
+
utf8: {
|
58
|
+
name: "utf8",
|
59
|
+
type: "hidden",
|
60
|
+
defaultValue: "\u0026#x2713;",
|
61
|
+
autocomplete: "off"
|
62
|
+
}
|
63
|
+
csrf: {
|
64
|
+
name: "utf8",
|
65
|
+
type: "authenticity_token",
|
66
|
+
defaultValue: "SomeTOken!23$",
|
67
|
+
autocomplete: "off"
|
68
|
+
}
|
69
|
+
},
|
70
|
+
inputs: {
|
71
|
+
name: {type: "text", defaultValue: "hello"},
|
72
|
+
submit: {type: "submit", value: "Update a Post"}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
```
|
77
|
+
|
78
|
+
You can then proceed to use this output in React like so:
|
79
|
+
|
80
|
+
```js
|
81
|
+
import React from 'react'
|
82
|
+
|
83
|
+
export default ({props, inputs, extras}) => {
|
84
|
+
<form {...props}>
|
85
|
+
{Object.values(extras).map((hiddenProps) => (<input {...hiddenProps} type="hidden"/>))}
|
86
|
+
|
87
|
+
<input {...inputs.name} type="text"/>
|
88
|
+
<label for={inputs.name.id}>Your Name</label>
|
89
|
+
|
90
|
+
<input {...inputs.submit} type="submit"/>
|
91
|
+
</form>
|
92
|
+
}
|
93
|
+
```
|
94
|
+
|
95
|
+
### Key format
|
96
|
+
By default, props_template automatically `camelize(:lower)` on all keys. All
|
97
|
+
documentation here reflects that default. You can change that [behavior](https://github.com/thoughtbot/props_template#change-key-format)
|
98
|
+
if you wish.
|
99
|
+
|
100
|
+
## Flexibility
|
101
|
+
FormProps is only concerned about attributes, the designer can focus on tag
|
102
|
+
structure and stay longer in HTML land. For example, you can decide to nest an
|
103
|
+
input inside a label.
|
104
|
+
|
105
|
+
```js
|
106
|
+
<label for={inputs.name.id}>
|
107
|
+
Your Name
|
108
|
+
<input {...inputs.name} type="text"/>
|
109
|
+
</label>
|
110
|
+
```
|
111
|
+
|
112
|
+
or not
|
113
|
+
|
114
|
+
```js
|
115
|
+
<label for={inputs.name.id}>Your Name</label>
|
116
|
+
<input {...inputs.name} />
|
117
|
+
```
|
118
|
+
|
119
|
+
## Custom Components
|
120
|
+
|
121
|
+
With `form_props` you can combine the comprehensiveness of Rails forms with
|
122
|
+
your prefered React components:
|
123
|
+
|
124
|
+
For example:
|
125
|
+
|
126
|
+
```js
|
127
|
+
json.some_form do
|
128
|
+
form_props(@post) do |f|
|
129
|
+
f.time_zone_select(:time_zone)
|
130
|
+
...
|
131
|
+
end
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
Then use it the props your own components or a external component like
|
136
|
+
`react-select`:
|
137
|
+
|
138
|
+
```js
|
139
|
+
import React from 'react'
|
140
|
+
import Select from 'react-select';
|
141
|
+
|
142
|
+
export default (({props, inputs, extras})) => {
|
143
|
+
return (
|
144
|
+
<form {...props}>
|
145
|
+
<Select
|
146
|
+
{...inputs.timeZone}
|
147
|
+
isMulti={inputs.timeZone.multiple}
|
148
|
+
/>
|
149
|
+
</form>
|
150
|
+
)
|
151
|
+
}
|
152
|
+
```
|
153
|
+
|
154
|
+
## Error handling
|
155
|
+
|
156
|
+
FormProps doesn't handle form errors, but you can easily add this functionality:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
json.someForm do
|
160
|
+
form_props(@post) do |f|
|
161
|
+
f.text_field :title
|
162
|
+
end
|
163
|
+
|
164
|
+
json.errors @post.errors.to_hash(true)
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
then merge it later
|
169
|
+
|
170
|
+
```js
|
171
|
+
<MyTextComponent {...someForm.inputs.title, error: ...someForm.errors.title}>
|
172
|
+
```
|
173
|
+
|
174
|
+
## form_props
|
175
|
+
`form_props` shares most of same arguments as [form_with]. The differences are
|
176
|
+
|
177
|
+
1. `remote` and `local` options are removed.
|
178
|
+
2. You can change the name of the value keys generated by the [form helpers](#form-helpers)
|
179
|
+
from `defaultValue` to `value`, by using `controlled: true`. For example:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
json.some_form do
|
183
|
+
form_props(@post, controlled: true) do |f|
|
184
|
+
f.text_field :title
|
185
|
+
end
|
186
|
+
end
|
187
|
+
```
|
188
|
+
|
189
|
+
By default, the `controlled` option is `false`.
|
190
|
+
|
191
|
+
###
|
192
|
+
|
193
|
+
`props` Attributes that you can splat direclty into your `<form>` element.
|
194
|
+
|
195
|
+
|
196
|
+
`extras` contain hidden input attributes that are created by form_props
|
197
|
+
indirectly, for example, the `csrf` token. Its best to wrap this in a custom
|
198
|
+
component that does the following. An [Extra] component is available
|
199
|
+
|
200
|
+
```js
|
201
|
+
Object.values(extras).map((hiddenProps) => (<input {...hiddenProps} type="hidden"/>))}
|
202
|
+
```
|
203
|
+
|
204
|
+
|
205
|
+
## Form Helpers
|
206
|
+
|
207
|
+
`form_props` provides its own version of the following Rails form helpers:
|
208
|
+
|
209
|
+
```
|
210
|
+
check_box file_field submit
|
211
|
+
collection_check_boxes grouped_collection_select tel_field
|
212
|
+
collection_helpers hidden_field text_area
|
213
|
+
collection_radio_buttons month_field text_field
|
214
|
+
collection_select number_field time_field
|
215
|
+
color_field password_field time_zone_select
|
216
|
+
date_field radio_button url_field
|
217
|
+
datetime_field range_field week_field
|
218
|
+
datetime_local_field search_field weekday_select
|
219
|
+
email_field select
|
220
|
+
```
|
221
|
+
|
222
|
+
`form_props` is a fork of `form_with`, and the accompanying form builder
|
223
|
+
inherits from `ActionView::Helpers::FormBuilder`.
|
224
|
+
|
225
|
+
Many of the helpers accept the same arguments and you can continue to rely on
|
226
|
+
[Rails Guides for form helpers] for guidance, but as the goal of `form_props`
|
227
|
+
is to focus on attributes instead of tags there are a few general differences
|
228
|
+
across all helpers that would beneficial to know:
|
229
|
+
|
230
|
+
1. The form helper `f.label` do not exist. Helpers like the below that `yield`s
|
231
|
+
for label structure
|
232
|
+
|
233
|
+
```
|
234
|
+
f.collection_radio_buttons(:active, [true, false], :to_s, :to_s) do |b|
|
235
|
+
b.label { b.radio_button + b.text }
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
no longer takes in blocks to do so.
|
240
|
+
|
241
|
+
2. `defaultValue`s are not escaped. Instead, we lean on PropsTemplate
|
242
|
+
to [escape] JSON and HTML entities.
|
243
|
+
3. `defaultValue` will not appear as a key if no `value` was set.
|
244
|
+
3. `data-disable-with` is removed on submit buttons.
|
245
|
+
4. `data-remote` is removed from form props.
|
246
|
+
5. For helpers selectively render hidden inputs, we passed the attribute to
|
247
|
+
5. `f.select` helpers does not render `selected` on `options`, instead it follows
|
248
|
+
react caveats and renders on the input's `value`. For example:
|
249
|
+
|
250
|
+
```js
|
251
|
+
{
|
252
|
+
"type": "select",
|
253
|
+
"name": "continent[countries]",
|
254
|
+
"id": "continent_countries",
|
255
|
+
"multiple": true,
|
256
|
+
"defaultValue": ["Africa", "Europe"],
|
257
|
+
"options": [
|
258
|
+
{"value": "Africa", "label": "Africa"},
|
259
|
+
{"value": "Europe", "label": "Europe"},
|
260
|
+
{"value": "America", "label": "America", "disabled": true}
|
261
|
+
]
|
262
|
+
}
|
263
|
+
```
|
264
|
+
|
265
|
+
### Unsupported helpers
|
266
|
+
`form_props` does **not** support:
|
267
|
+
|
268
|
+
`label`. We encourage you to use the tag directly in combination with other
|
269
|
+
helpers. For example:
|
270
|
+
|
271
|
+
```
|
272
|
+
<label for={inputs.name.id} />
|
273
|
+
```
|
274
|
+
|
275
|
+
`rich_text_area`. We encourage you to use the `f.text_area` helper in
|
276
|
+
combination with Trix wrapped in React, or TinyMCE's react component.
|
277
|
+
|
278
|
+
`button`. We encourage you to use the tag directly.
|
279
|
+
|
280
|
+
`date_select`, `time_select`, `datetime_select`. We encourage you to use other
|
281
|
+
alternatives like `react-date-picker` in combination with other supported date
|
282
|
+
field helpers.
|
283
|
+
|
284
|
+
## Text helpers
|
285
|
+
|
286
|
+
[text_field], [email_field], [tel_field], [file_field], [url_field],
|
287
|
+
[hidden_field], and the slight variations [password_field],
|
288
|
+
[search_field], [color_field] has the same arguments as their Rails
|
289
|
+
counterpart.
|
290
|
+
|
291
|
+
When used like so
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
form_props(model: @post) do |f|
|
295
|
+
f.text_field(:title)
|
296
|
+
end
|
297
|
+
```
|
298
|
+
|
299
|
+
`inputs.title` would output
|
300
|
+
|
301
|
+
```
|
302
|
+
{
|
303
|
+
"type": "text",
|
304
|
+
"defaultValue": "Hello World",
|
305
|
+
"name": "post[title]",
|
306
|
+
"id": "post_title"
|
307
|
+
}
|
308
|
+
```
|
309
|
+
|
310
|
+
## Date helpers
|
311
|
+
[date_field], [datetime_field], [datetime_local_field], [month_field],
|
312
|
+
[week_field] has the same arguments as their Rails counterparts.
|
313
|
+
|
314
|
+
When used like so
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
form_props(model: @post) do |f|
|
318
|
+
f.datetime_field(:created_at)
|
319
|
+
end
|
320
|
+
```
|
321
|
+
|
322
|
+
`inputs.created_at` would output
|
323
|
+
|
324
|
+
```json
|
325
|
+
{
|
326
|
+
"type": "datetime-local",
|
327
|
+
"defaultValue": "2004-06-15T01:02:03",
|
328
|
+
"name": "post[created_at]",
|
329
|
+
"id": "post_created_at"
|
330
|
+
}
|
331
|
+
```
|
332
|
+
|
333
|
+
## Number helpers
|
334
|
+
[number_field], [range_field] has the same arguments as their Rails counterparts.
|
335
|
+
|
336
|
+
When used like so
|
337
|
+
|
338
|
+
```ruby
|
339
|
+
@post.favs = 2
|
340
|
+
|
341
|
+
form_props(model: @post) do |f|
|
342
|
+
f.range_field(:favs, in: 1...10)
|
343
|
+
end
|
344
|
+
```
|
345
|
+
|
346
|
+
`inputs.favs` would output
|
347
|
+
|
348
|
+
```json
|
349
|
+
{
|
350
|
+
"type": "range",
|
351
|
+
"defaultValue": "2",
|
352
|
+
"name": "post[favs]",
|
353
|
+
"min": 1,
|
354
|
+
"max": 9,
|
355
|
+
"id": "post_favs"
|
356
|
+
}
|
357
|
+
```
|
358
|
+
|
359
|
+
## Checkbox helper
|
360
|
+
[check_box] has the same arguments its Rails counterpart.
|
361
|
+
|
362
|
+
The original Rails `check_box` helper renders an unchecked value in a
|
363
|
+
hidden input. While `form_props` doesn't generate the tags, the
|
364
|
+
`unchecked_value`, and `include_hidden` can be passed to a React component
|
365
|
+
to replicate that behavior. This repository has an example [CheckBox]
|
366
|
+
component used in its test that you can refer to.
|
367
|
+
|
368
|
+
When used like so:
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
@post.admin = "on"
|
372
|
+
|
373
|
+
form_props(model: @post) do |f|
|
374
|
+
f.check_box(:admin, {}, "on", "off")
|
375
|
+
end
|
376
|
+
```
|
377
|
+
|
378
|
+
`inputs.admin` would output
|
379
|
+
|
380
|
+
```json
|
381
|
+
{
|
382
|
+
"type": "checkbox",
|
383
|
+
"defaultValue": "on",
|
384
|
+
"uncheckedValue": "off",
|
385
|
+
"name": "post[admin]",
|
386
|
+
"id": "post_admin",
|
387
|
+
"includeHidden": true
|
388
|
+
}
|
389
|
+
```
|
390
|
+
|
391
|
+
## Radio helper
|
392
|
+
[radio_button] has the same arguments as its Rails counterpart. The radio button is unique
|
393
|
+
|
394
|
+
When used like so:
|
395
|
+
|
396
|
+
```ruby
|
397
|
+
@post.admin = false
|
398
|
+
|
399
|
+
form_props(model: @post) do |f|
|
400
|
+
f.radio_button(:admin, true)
|
401
|
+
f.radio_button(:admin, false)
|
402
|
+
end
|
403
|
+
```
|
404
|
+
|
405
|
+
The keys on `inputs` are a combination of the name and value. So `inputs.adminTrue`
|
406
|
+
would output:
|
407
|
+
|
408
|
+
```json
|
409
|
+
{
|
410
|
+
"type": "radio",
|
411
|
+
"defaultValue": "true",
|
412
|
+
"name": "post[admin]",
|
413
|
+
"id": "post_admin_true"
|
414
|
+
}
|
415
|
+
```
|
416
|
+
|
417
|
+
and `inputs.adminFalse` would output
|
418
|
+
|
419
|
+
```json
|
420
|
+
{
|
421
|
+
"type": "radio",
|
422
|
+
"defaultValue": "false",
|
423
|
+
"name": "post[admin]",
|
424
|
+
"id": "post_admin_false",
|
425
|
+
"checked": true
|
426
|
+
}
|
427
|
+
```
|
428
|
+
|
429
|
+
## Select helpers
|
430
|
+
[select], [weekday_select], [time_zone_select] mostly has the same arguments
|
431
|
+
as its Rails counterpart. They key difference is that choices for select cannot be a string:
|
432
|
+
|
433
|
+
```ruby
|
434
|
+
# BAD!!!
|
435
|
+
|
436
|
+
form_props(model: @post) do |f|
|
437
|
+
f.select(:category, "<option><option/>", multiple: false)
|
438
|
+
end
|
439
|
+
|
440
|
+
# Good
|
441
|
+
|
442
|
+
form_props(model: @post) do |f|
|
443
|
+
f.select(:category, [], multiple: false)
|
444
|
+
end
|
445
|
+
```
|
446
|
+
|
447
|
+
When used like so
|
448
|
+
|
449
|
+
```ruby
|
450
|
+
@post.category = "lifestyle"
|
451
|
+
|
452
|
+
form_props(model: @post) do |f|
|
453
|
+
f.select(:category, ["lifestyle", "programming", "spiritual"], {selected: "", disabled: "", prompt: "Choose one"}, {required: true})
|
454
|
+
end
|
455
|
+
|
456
|
+
```
|
457
|
+
|
458
|
+
`inputs.category` would output
|
459
|
+
|
460
|
+
```
|
461
|
+
{
|
462
|
+
"type": "select",
|
463
|
+
"required": true,
|
464
|
+
"name": "post[category]",
|
465
|
+
"id": "post_category",
|
466
|
+
"defaultValue":"lifestyle",
|
467
|
+
"options": [
|
468
|
+
{"disabled": true, "value": "", "label": "Choose one"},
|
469
|
+
{"value": "lifestyle", "label": "lifestyle"},
|
470
|
+
{"value": "programming", "label": "programming"},
|
471
|
+
{"value": "spiritual", "label": "spiritual"}
|
472
|
+
]
|
473
|
+
}
|
474
|
+
```
|
475
|
+
|
476
|
+
Of note:
|
477
|
+
1. Notice that we follow react caveats and put `selected` values on `defaultValue`. This rule
|
478
|
+
does not apply to the `disabled` attribute on option.
|
479
|
+
2. When `multiple: true`, `defaultValue` is an array of values.
|
480
|
+
3. The key, `defaultValue` is only set if the value is in options. For example:
|
481
|
+
|
482
|
+
```
|
483
|
+
form_props(model: @post) do |f|
|
484
|
+
f.select(:category, [])
|
485
|
+
end
|
486
|
+
```
|
487
|
+
|
488
|
+
would output in `inputs.category`:
|
489
|
+
|
490
|
+
```
|
491
|
+
{
|
492
|
+
"type": "select",
|
493
|
+
"name": "post[category]",
|
494
|
+
"id": "post_category",
|
495
|
+
"options": []
|
496
|
+
}
|
497
|
+
```
|
498
|
+
|
499
|
+
As the `select` helper renders nested options and `includeHidden`, a custom
|
500
|
+
component is required to correctly render the tag structure. A reference
|
501
|
+
[Select component] implementation is availble that is used in our tests.
|
502
|
+
|
503
|
+
The `select` helper can also output a grouped collection.
|
504
|
+
|
505
|
+
```ruby
|
506
|
+
@post = Post.new
|
507
|
+
countries_by_continent = [
|
508
|
+
["<Africa>", [["<South Africa>", "<sa>"], ["Somalia", "so"]]],
|
509
|
+
["Europe", [["Denmark", "dk"], ["Ireland", "ie"]]]
|
510
|
+
]
|
511
|
+
|
512
|
+
form_props(model: @post) do |f|
|
513
|
+
f.select(:category, countries_by_continent)
|
514
|
+
end
|
515
|
+
```
|
516
|
+
|
517
|
+
`inputs.category` would output:
|
518
|
+
|
519
|
+
```json
|
520
|
+
{
|
521
|
+
"type": "select",
|
522
|
+
"name": "post[category]",
|
523
|
+
"id": "post_category",
|
524
|
+
"options": [
|
525
|
+
{
|
526
|
+
"label": "<Africa>", "options": [
|
527
|
+
{"value": "<sa>", "label": "<South Africa>"},
|
528
|
+
{"value": "so", "label": "Somalia"}
|
529
|
+
]
|
530
|
+
},
|
531
|
+
{
|
532
|
+
"label": "Europe", "options": [
|
533
|
+
{"value": "dk", "label": "Denmark"},
|
534
|
+
{"value": "ie", "label": "Ireland"}
|
535
|
+
]
|
536
|
+
}
|
537
|
+
]
|
538
|
+
}
|
539
|
+
```
|
540
|
+
|
541
|
+
|
542
|
+
## Group collection select
|
543
|
+
[group_collection_select] has the same arguments its Rails counterpart.
|
544
|
+
|
545
|
+
Like `select`, you'll need combine this with a custom `Select` component. An
|
546
|
+
example [Select component] is available.
|
547
|
+
|
548
|
+
When used like so:
|
549
|
+
|
550
|
+
```ruby
|
551
|
+
|
552
|
+
@post = Post.new
|
553
|
+
@post.country = "dk"
|
554
|
+
label_proc = proc { |c| c.id }
|
555
|
+
|
556
|
+
continents = [
|
557
|
+
Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")]),
|
558
|
+
Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")])
|
559
|
+
]
|
560
|
+
|
561
|
+
form_props(model: @post) do |f|
|
562
|
+
f.grouped_collection_select(
|
563
|
+
:country, continents, "countries", label_proc, "country_id", "country_name"
|
564
|
+
)
|
565
|
+
end
|
566
|
+
```
|
567
|
+
|
568
|
+
`inputs.country` would output
|
569
|
+
|
570
|
+
```json
|
571
|
+
{
|
572
|
+
"name": "post[country]",
|
573
|
+
"id": "post_country",
|
574
|
+
"type": "select",
|
575
|
+
"defaultValue": "dk",
|
576
|
+
"options": [
|
577
|
+
{
|
578
|
+
"label":"<Africa>",
|
579
|
+
"options": [
|
580
|
+
{"value": "<sa>", "label": "<South Africa>"},
|
581
|
+
{"value": "so", "label": "Somalia"}
|
582
|
+
]
|
583
|
+
}, {
|
584
|
+
"label": "Europe",
|
585
|
+
"options": [
|
586
|
+
{"value": "dk", "label": "Denmark"},
|
587
|
+
{"value":"ie", "label": "Ireland"}
|
588
|
+
]
|
589
|
+
}
|
590
|
+
]
|
591
|
+
}
|
592
|
+
```
|
593
|
+
|
594
|
+
## Collection select
|
595
|
+
[collection_select], [collection_radio_buttons], and [collection_check_boxes]
|
596
|
+
has the same arguments its Rails counterpart, but their output differs slightly.
|
597
|
+
|
598
|
+
|
599
|
+
[collection_select] follows the same output as `f.select`. When used like so:
|
600
|
+
|
601
|
+
```
|
602
|
+
dummy_posts = [
|
603
|
+
Post.new(1, "<Abe> went home", "<Abe>", "To a little house", "shh!"),
|
604
|
+
Post.new(2, "Babe went home", "Babe", "To a little house", "shh!"),
|
605
|
+
Post.new(3, "Cabe went home", "Cabe", "To a little house", "shh!")
|
606
|
+
]
|
607
|
+
|
608
|
+
|
609
|
+
form_props(model: @post) do |f|
|
610
|
+
f.collection_select(:author_name, dummy_posts, "author_name", "author_name")
|
611
|
+
end
|
612
|
+
```
|
613
|
+
|
614
|
+
`inputs.authorName` would output:
|
615
|
+
|
616
|
+
```
|
617
|
+
{
|
618
|
+
"type": "select",
|
619
|
+
"name": "post[author_name]",
|
620
|
+
"id": "post_author_name",
|
621
|
+
"defaultValue": "Babe",
|
622
|
+
"options": [
|
623
|
+
{"value": "<Abe>", "label": "<Abe>"},
|
624
|
+
{"value": "Babe", "label": "Babe"},
|
625
|
+
{"value": "Cabe", "label": "Cabe"}
|
626
|
+
]
|
627
|
+
}
|
628
|
+
```
|
629
|
+
|
630
|
+
[collection_radio_buttons] and [collection_check_boxes] usage is the same with
|
631
|
+
their rails counterpart, and when used, would render:
|
632
|
+
|
633
|
+
```
|
634
|
+
{
|
635
|
+
"collection": [
|
636
|
+
{"name":"user[other_category_ids][]","type": "checkbox", "defaultValue": "1", "uncheckedValue":"","id":"user_category_ids_1","label": "Category 1"},
|
637
|
+
{"name":"user[other_category_ids][]","type": "checkbox", "defaultValue": "2", "uncheckedValue":"","id":"user_category_ids_2","label": "Category 2"}
|
638
|
+
],
|
639
|
+
"name": "user[other_category_ids][]",
|
640
|
+
"includeHidden": true
|
641
|
+
}
|
642
|
+
```
|
643
|
+
|
644
|
+
Like select, you would need a custom component to render. An example
|
645
|
+
implementation for [CollectionCheckBoxes] and [CollectionRadioButtons] are
|
646
|
+
available.
|
647
|
+
|
648
|
+
## jbuilder
|
649
|
+
|
650
|
+
form_props can work with jbuilder, but needs an extra call in the beginning of
|
651
|
+
your template to `FormProps.set` to inject `json`. For example.
|
652
|
+
|
653
|
+
```ruby
|
654
|
+
FormProps.set(json, self)
|
655
|
+
|
656
|
+
json.data do
|
657
|
+
json.hello "world"
|
658
|
+
|
659
|
+
json.form do
|
660
|
+
form_props(model: User.new, url: "/") do |f|
|
661
|
+
f.text_field(:email)
|
662
|
+
f.submit
|
663
|
+
end
|
664
|
+
end
|
665
|
+
end
|
666
|
+
```
|
667
|
+
|
668
|
+
[escape]: https://github.com/thoughtbot/props_template#escape-mode
|
669
|
+
[form_with]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-form_with
|
670
|
+
[Extra]: ./components/Extras.js
|
671
|
+
[CollectionCheckBoxes]: ./components/CollectionCheckBoxes.js
|
672
|
+
[CollectionRadioButtons]: ./components/CollectionRadioButtons.js
|
673
|
+
[Select Component]: ./components/Select.js
|
674
|
+
[select]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormBuilder.html#method-i-select
|
675
|
+
[CheckBox]: ./components/CheckBox.js
|
676
|
+
[PropsTemplate]: https://github.com/thoughtbot/props_template
|
677
|
+
[text_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-text_field
|
678
|
+
[tel_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-tel_field
|
679
|
+
[file_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-file_field
|
680
|
+
[week_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-week_field
|
681
|
+
[url_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-url_field
|
682
|
+
[telephone_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-telephone_field
|
683
|
+
[text_area]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-text_area
|
684
|
+
[text_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-text_field
|
685
|
+
[time_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-time_field
|
686
|
+
[search_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-search_field
|
687
|
+
[radio_button]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-radio_button
|
688
|
+
[range_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-range_field
|
689
|
+
[password_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-password_field
|
690
|
+
[phone_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-phone_field
|
691
|
+
[number_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-number_field
|
692
|
+
[month_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-month_field
|
693
|
+
[hidden_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-hidden_field
|
694
|
+
[fields]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-fields
|
695
|
+
[fields_for]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
|
696
|
+
[field_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-file_field
|
697
|
+
[form_with]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-form_with
|
698
|
+
[email_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-email_field
|
699
|
+
[date_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-date_field
|
700
|
+
[datetime_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-datetime_field
|
701
|
+
[datetime_local_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-datetime_local_field
|
702
|
+
[check_box]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-check_box
|
703
|
+
[color_field]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormHelper.html#method-i-color_field
|
704
|
+
[grouped_collection_select]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-grouped_collection_select
|
705
|
+
[collection_radio_buttons]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormBuilder.html#method-i-collection_radio_buttons
|
706
|
+
[collection_select]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormBuilder.html#method-i-collection_select
|
707
|
+
[collection_check_boxes]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormBuilder.html#method-i-collection_check_boxes
|
708
|
+
[weekday_select]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormBuilder.html#method-i-weekday_select
|
709
|
+
[group_collection_select]: https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/FormBuilder.html#method-i-grouped_collection_select
|
710
|
+
|
711
|
+
## Special Thanks
|
712
|
+
|
713
|
+
Thanks to [bootstrap_form](https://github.com/bootstrap-ruby/bootstrap_form) documentation for inspiration.
|
714
|
+
|