bullet_train 1.5.1 → 1.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/docs/field-partials/address-field.md +28 -0
- data/docs/field-partials/buttons.md +9 -0
- data/docs/field-partials/dynamic-forms-dependent-fields.md +123 -0
- data/docs/field-partials/super-select.md +9 -0
- data/docs/field-partials.md +32 -19
- data/lib/bullet_train/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26d50ad6167e3e1f7d3b8a550313094548a2b82bba8c60106ec8549db38abd51
|
4
|
+
data.tar.gz: ffe18a2a1265a052929fc52bd9213de99f565327384d022bf644b43cb4aa3174
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7e1ddd05c6a9bebad198f5cf6e48db86e09fa8194ef8ae5cc83bb12a141efe174716ea98b6b6b3032cc13a4d466dd6ed3a85dd044643aa717c3a72a58ba5c75
|
7
|
+
data.tar.gz: 04c8e18fea2b7db8ed9e08876cfa2f0fb51264f99c4cfb1a54323bb3497f3c7f2a42a4699cadaefe8ca639f42a78391138b79424e3a8493de6721efa85e6fbb2
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Examples for the `address_field` Field Partial
|
2
|
+
|
3
|
+
The address field partial adds a block of fields to your form. It creates and stores an instance of the `Address` model and associates it to your record.
|
4
|
+
|
5
|
+
## Sub-Fields Included in the Partial
|
6
|
+
|
7
|
+
| Field Label | Name | Data Type | Notes |
|
8
|
+
|---------------------------|---------------|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
9
|
+
| Country | `country_id` | `Addresses::Country` | For country values, see `config/address/countries.json` in bullet_train-core/bullet_train. |
|
10
|
+
| Address | `address_one` | `string` | |
|
11
|
+
| Address (cont'd) | `address_two` | `string` | |
|
12
|
+
| City | `city` | `string` | |
|
13
|
+
| State / Province / Region | `region_id` | `Addresses::Region` | Depending on the country selected, the label will change (e.g. Prefecture for Japan, Province or Territory for Canada). For all region values, see `config/addresses/states.json` in bullet_train-core/bullet_train. |
|
14
|
+
| Postal code | `postal_code` | `string` | Depending on the country selected, the label will change (e.g. Zip code for the United States). |
|
15
|
+
|
16
|
+
If you'd like to add or remove fields, you'll need to update your own version of the `Address` model and eject and modify the `shared/fields/address_field` partial.
|
17
|
+
|
18
|
+
## Dynamically Updating `region_id` and `postal_code` Fields and Labels
|
19
|
+
|
20
|
+
The `address_field` partial implements Bullet Train's [Dependent Fields Pattern](/docs/field-partials/dynamic-forms-dependent-fields.md) to automatically update the `region_id` and `postal_code` fields and their labels based on the value of the selected `country_id`.
|
21
|
+
|
22
|
+
## Customizing the Address Output
|
23
|
+
|
24
|
+
By default, `show` screens get a multi-line output and `index` table columns get a one-line format (use the `one_line: true` param).
|
25
|
+
|
26
|
+
To customize this output, eject the `shared/attributes/address` partial.
|
27
|
+
|
28
|
+
See the [Showcase preview](https://github.com/bullet-train-co/showcase)<i class="ti ti-new-window ml-2"></i> for the example output.
|
@@ -40,3 +40,12 @@ You can allow multiple buttons to be selected using the `multiple` option, like
|
|
40
40
|
<%= render 'shared/fields/buttons', form: form, method: :category_ids,
|
41
41
|
options: Category.all.map { |category| [category.id, category.label_string] }, multiple: true %>
|
42
42
|
```
|
43
|
+
|
44
|
+
## Dynamically Updating Form Fields
|
45
|
+
|
46
|
+
If you'd like to:
|
47
|
+
|
48
|
+
* modify other fields based on the value of your `buttons` field, or
|
49
|
+
* modify your `buttons` field based on the value of other fields
|
50
|
+
|
51
|
+
See [Dynamic Forms and Dependent Fields](/docs/field-partials/dynamic-forms-dependent-fields.md).
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# Dynamic Forms and Dependent Fields
|
2
|
+
|
3
|
+
Bullet Train introduces two new concepts to make your Hotwire-powered forms update dynamically on field changes.
|
4
|
+
|
5
|
+
1. Dependent Fields Pattern
|
6
|
+
2. Dependent Fields Frame
|
7
|
+
|
8
|
+
## Dependent Fields Pattern
|
9
|
+
|
10
|
+
Let's say we have a `super_select` for a "Where have you heard from us?" field. And we'll have a `text_field` for "Other", `disabled` by default.
|
11
|
+
|
12
|
+
```erb
|
13
|
+
<%= render 'shared/fields/super_select',
|
14
|
+
method: :heard_from,
|
15
|
+
options: {include_blank: true},
|
16
|
+
other_options: {search: true}
|
17
|
+
%>
|
18
|
+
<%= render 'shared/fields/text_field',
|
19
|
+
method: :heard_from_other,
|
20
|
+
options: {disabled: true}
|
21
|
+
%>
|
22
|
+
```
|
23
|
+
|
24
|
+
Our goal: if `other` is selected, enable the "Other" field.
|
25
|
+
|
26
|
+
We'll wire the `super_select` field with the `dependable` Stimulus controller. We'll also tie both fields using the `dependable-dependents-selector-value`. In this case, the `id` of the the `heard_from_other` field.
|
27
|
+
|
28
|
+
```erb
|
29
|
+
<%= render 'shared/fields/super_select',
|
30
|
+
method: :heard_from,
|
31
|
+
options: {include_blank: true},
|
32
|
+
other_options: {search: true},
|
33
|
+
wrapper_options: {
|
34
|
+
data: {
|
35
|
+
'controller': "dependable",
|
36
|
+
'action': '$change->dependable#updateDependents',
|
37
|
+
'dependable-dependents-selector-value': "##{form.field_id(:heard_from_other)}"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
%>
|
41
|
+
<%= render 'shared/fields/text_field',
|
42
|
+
method: :heard_from_other,
|
43
|
+
id: form.field_id(:heard_from_other),
|
44
|
+
options: {disabled: true}
|
45
|
+
%>
|
46
|
+
```
|
47
|
+
|
48
|
+
On `$change` ([See `super_select` dispatched events](/docs/field-partials/super-select#events)), a custom `dependable:updated` event will be dispatched to all elements matching the `dependable-dependents-selector-value`. This gives us flexibility: disparate form fields don't need to be wrapped with a common Stimulus controlled-wrapper. This approach is favored over Stimulus `outlets` because here we're not coupling the functionality of the `dependable` and `dependent` fields. We're just dispatching Custom Events and using CSS selectors, preferably good old `form.field_id`'s.
|
49
|
+
|
50
|
+
To let our `:heard_from_other` field handle the `dependable:updated` event, we'll assume we have created a custom `field-availability` Stimulus controller, with a `#toggle` method, looking for the `expected` value on the incoming event `target` element, in this case the `dependable` field.
|
51
|
+
|
52
|
+
```erb
|
53
|
+
<%= render 'shared/fields/text_field',
|
54
|
+
method: :heard_from_other,
|
55
|
+
id: form.field_id(:heard_from_other),
|
56
|
+
options: {disabled: true},
|
57
|
+
data: {
|
58
|
+
controller: "field-availability",
|
59
|
+
action: "dependable:updated->field-availability#toggle",
|
60
|
+
field_availability_expected_value: "other"
|
61
|
+
}
|
62
|
+
%>
|
63
|
+
```
|
64
|
+
|
65
|
+
Note: `field-availability` here is not implemented in Bullet Train. It serves as an example.
|
66
|
+
|
67
|
+
Next, we'll find a way to only serve the `:heard_from_other` field to the user if "other" is selected, this time by using server-side conditionals in a `turbo_frame`.
|
68
|
+
|
69
|
+
## Dependent Fields Frame
|
70
|
+
|
71
|
+
What if you'd instead want to:
|
72
|
+
|
73
|
+
* Not rely on a custom Stimulus controller to control the `disabled` state of the "Other" field
|
74
|
+
* Show/hide multiple dependent fields based on the value of the `dependable` field.
|
75
|
+
* Update more than the field itself, but also the value of its `label`. As an example, the [`address_field`](/docs/field-partials/address-field.md) partial shows an empty "State / Province / Region" sub-field by default, and on changing the `:country_id` field to the United States, changes the whole `:region_id` to "State" as its label and with all US States as its choices.
|
76
|
+
|
77
|
+
For these situations, Bullet Train has a `dependent_fields_turbo_frame` partial that's made to listen to `dependable:updated` events by default.
|
78
|
+
|
79
|
+
```erb
|
80
|
+
# update the super-select `dependable-dependents-selector-value` to "##{form.field_id(:heard_from, :dependent_fields)}" to match
|
81
|
+
|
82
|
+
<%= render "shared/fields/dependent_fields_frame",
|
83
|
+
id: form.field_id(:heard_from, :dependent_fields),
|
84
|
+
form: form,
|
85
|
+
dependable_fields: [:heard_from] do %>
|
86
|
+
|
87
|
+
<% if form.object&.heard_from == "other" %>
|
88
|
+
<%# no need for a custom `id` or the `disabled` attribute %>
|
89
|
+
<%= render 'shared/fields/text_field', method: :heard_from_other %>
|
90
|
+
<% end %>
|
91
|
+
|
92
|
+
<%# include additional fields if "other" is selected %>
|
93
|
+
<% end %>
|
94
|
+
```
|
95
|
+
|
96
|
+
This `dependent_fields_frame` serves two purposes:
|
97
|
+
|
98
|
+
1. Handle the `dependable:updated` event, so that the frame can...
|
99
|
+
2. Re-fetch the current form URL (it could be for a `#new` or a `#edit`, it works in both situations) with a GET request (not a submit) that contains the `heard_from` value as a `query_string` param. It then ensures that our `form.object.heard_from` value gets populated with the value found in the `query_string` param automatically, with **no changes needed to the resource controller**. That's all handled by the `dependent_fields_frame` partial by reading its `dependable_fields` param.
|
100
|
+
|
101
|
+
With this functionality, the contents of the underlying `turbo_frame` will be populated with the updated fields.
|
102
|
+
|
103
|
+
---
|
104
|
+
|
105
|
+
Now let's say we want to come back to the `disabled` use case above, while using the `dependent_fields_frame` approach.
|
106
|
+
|
107
|
+
We'll move the conditional on the `disabled` property. And we'll also let the `dependent_fields_frame` underlying controller handle disabling the field automatically when the `turbo_frame` awaits updates.
|
108
|
+
|
109
|
+
```erb
|
110
|
+
<%= render "shared/fields/dependent_fields_frame",
|
111
|
+
id: form.field_id(:heard_from, :dependent_fields),
|
112
|
+
form: form,
|
113
|
+
dependable_fields: [:heard_from] do |dependent_fields_controller_name| %>
|
114
|
+
|
115
|
+
<%= render 'shared/fields/text_field',
|
116
|
+
method: :heard_from_other,
|
117
|
+
options: {disabled: form.object&.heard_from != "other"},
|
118
|
+
data: {"#{dependent_fields_controller_name}-target": "field"}
|
119
|
+
%>
|
120
|
+
<% end %>
|
121
|
+
```
|
122
|
+
|
123
|
+
To learn more about its inner functionality, search the `bullet-train-core` repo for `dependable_controller.js`, `dependent_fields_frame_controller.js` and `_dependent_fields_frame.html.erb`. You can also see an implementation by looking at the `_address_field.html.erb` partial.
|
@@ -144,3 +144,12 @@ You can pass these options to the super select partial like so:
|
|
144
144
|
```
|
145
145
|
|
146
146
|
*Passing options like this doesn't allow JS callbacks or functions to be used, so you must extend the Stimulus controller and add options to the `optionsOverride` getter if you want to do so.
|
147
|
+
|
148
|
+
## Dynamically Updating Form Fields
|
149
|
+
|
150
|
+
If you'd like to:
|
151
|
+
|
152
|
+
* modify other fields based on the value of your `super_select`, or
|
153
|
+
* modify your `super_select` based on the value of other fields
|
154
|
+
|
155
|
+
See [Dynamic Forms and Dependent Fields](/docs/field-partials/dynamic-forms-dependent-fields.md).
|
data/docs/field-partials.md
CHANGED
@@ -122,25 +122,26 @@ Certain form field partials like `buttons` and `super_select` can also have thei
|
|
122
122
|
|
123
123
|
## Available Field Partials
|
124
124
|
|
125
|
-
| Field Partial
|
126
|
-
|
127
|
-
| `
|
128
|
-
|
|
129
|
-
| `
|
130
|
-
| `
|
131
|
-
| `
|
132
|
-
| `
|
133
|
-
| `
|
134
|
-
| `
|
135
|
-
|
|
136
|
-
| `
|
137
|
-
| `
|
138
|
-
| `
|
139
|
-
|
|
140
|
-
| `
|
141
|
-
| `
|
142
|
-
| `
|
143
|
-
| `
|
125
|
+
| Field Partial | Data Type | Multiple Values? | Assignment Helpers | JavaScript Library | Description |
|
126
|
+
|----------------------------------------------------------|---------------------------|------------------|-------------------------|-----------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
|
127
|
+
| [`address_field`](/docs/field-partials/address-field.md) | `Address` | | | | Adds a block of address fields. On change, its country super-select auto-updates the state/province/region super-select and postal/zip code field label. |
|
128
|
+
| `boolean` | `boolean` | | `assign_boolean` | | |
|
129
|
+
| [`buttons`](/docs/field-partials/buttons.md) | `string` | Optionally | `assign_checkboxes` | | |
|
130
|
+
| `image` | `string` or `attachment`* | | | | |
|
131
|
+
| `color_picker` | `string` | | | [pickr](https://simonwep.github.io/pickr/) | |
|
132
|
+
| `date_and_time_field` | `datetime` | | | [Date Range Picker](https://www.daterangepicker.com) | |
|
133
|
+
| `date_field` | `date` | | | [Date Range Picker](https://www.daterangepicker.com) | |
|
134
|
+
| `email_field` | `string` | | | | |
|
135
|
+
| `emoji_field` | `string` | | | [Emoji Mart](https://missiveapp.com/open/emoji-mart) | A front-end library which allows users to browse and select emojis with ease. | |
|
136
|
+
| [`file_field`](/docs/field-partials/file-field.md) | `attachment` | | | [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) | |
|
137
|
+
| `options` | `string` | Optionally | `assign_checkboxes` | | |
|
138
|
+
| `password_field` | `string` | | | | |
|
139
|
+
| `phone_field` | `string` | | | [International Telephone Input](https://intl-tel-input.com) | Ensures telephone numbers are in a format that can be used by providers like Twilio. |
|
140
|
+
| [`super_select`](/docs/field-partials/super-select.md) | `string` | Optionally | `assign_select_options` | [Select2](https://select2.org) | Provides powerful option search, AJAX search, and multi-select functionality. |
|
141
|
+
| `text_area` | `text` | | | | |
|
142
|
+
| `text_field` | `string` | | | | |
|
143
|
+
| `number_field` | `integer` | | | | |
|
144
|
+
| `trix_editor` | `text` | | | [Trix](https://github.com/basecamp/trix) | Basic HTML-powered formatting features and support for at-mentions amongst team members. |
|
144
145
|
|
145
146
|
* The data type for `image` fields will vary based on whether you're using Cloudinary or ActiveStorage.
|
146
147
|
For Cloudinary you should use `string`, and for ActiveStorage you should use `attachment`.
|
@@ -161,7 +162,19 @@ After Super Scaffolding a `date` or `date_and_time` field, you can pass a format
|
|
161
162
|
|
162
163
|
Please refer to the [Ruby on Rails documentation](https://guides.rubyonrails.org/i18n.html#adding-date-time-formats) for more information.
|
163
164
|
|
165
|
+
## Dynamic Forms and Dependent Fields
|
166
|
+
|
167
|
+
To dynamically update your forms on field changes, Bullet Train introduces two new concepts:
|
168
|
+
|
169
|
+
1. Dependent Fields Pattern
|
170
|
+
2. Dependent Fields Frame
|
171
|
+
|
172
|
+
These concepts are currently used by the `address_field` to dynamically update the _State / Province / Region_ field on _Country_ change, as well as the label for the _Postal Code_ field.
|
173
|
+
|
174
|
+
[Read more about Dynamic Forms and Dependent Fields](/docs/field-partials/dynamic-forms-dependent-fields.md)
|
175
|
+
|
164
176
|
## Additional Field Partials Documentation
|
177
|
+
- [`address_field`](/docs/field-partials/address-field.md)
|
165
178
|
- [`buttons`](/docs/field-partials/buttons.md)
|
166
179
|
- [`super_select`](/docs/field-partials/super-select.md)
|
167
180
|
- [`file_field`](/docs/field-partials/file-field.md)
|
data/lib/bullet_train/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet_train
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: standard
|
@@ -725,8 +725,10 @@ files:
|
|
725
725
|
- docs/billing/usage.md
|
726
726
|
- docs/desktop.md
|
727
727
|
- docs/field-partials.md
|
728
|
+
- docs/field-partials/address-field.md
|
728
729
|
- docs/field-partials/buttons.md
|
729
730
|
- docs/field-partials/date-related-fields.md
|
731
|
+
- docs/field-partials/dynamic-forms-dependent-fields.md
|
730
732
|
- docs/field-partials/file-field.md
|
731
733
|
- docs/field-partials/super-select.md
|
732
734
|
- docs/font-awesome-pro.md
|