form_props 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|