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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28b3ba5f50dac3b25183a892b754c22e23ff75a757293050c3124401037e5fd9
4
- data.tar.gz: 20c4f020b91dabe7a2bc85f006de605d187d71a943976a2f6eeb729cebb2dba5
3
+ metadata.gz: 26d50ad6167e3e1f7d3b8a550313094548a2b82bba8c60106ec8549db38abd51
4
+ data.tar.gz: ffe18a2a1265a052929fc52bd9213de99f565327384d022bf644b43cb4aa3174
5
5
  SHA512:
6
- metadata.gz: 88d77c764443e6de40f3ef8187c0add73aa76b4a3d1fc605dabba7335031a227b280d7db58ebf4ec5f4baf8087e9d1e1b54e3d364bccd5332337e2a23638ac74
7
- data.tar.gz: d12805a0a7a1bfb764e867d03d898062ea67423882786805ce60407fc5176eabacc10dbc94654f96279bde26cb38d3bfdb3c20ddd5f3a73323a492df43bec6ea
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).
@@ -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 | Data Type | Multiple Values? | Assignment Helpers | JavaScript Library | Description |
126
- |--------------------------------------------------------|--------------|------------------|-------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
127
- | `boolean` | `boolean` | | `assign_boolean` | | |
128
- | [`buttons`](/docs/field-partials/buttons.md) | `string` | Optionally | `assign_checkboxes` | | |
129
- | `image` | `string` or `attachment`* | | | | |
130
- | `color_picker` | `string` | | | [pickr](https://simonwep.github.io/pickr/) | |
131
- | `date_and_time_field` | `datetime` | | | [Date Range Picker](https://www.daterangepicker.com) | |
132
- | `date_field` | `date` | | | [Date Range Picker](https://www.daterangepicker.com) | |
133
- | `email_field` | `string` | | | | |
134
- | `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. | |
135
- | [`file_field`](/docs/field-partials/file-field.md) | `attachment` | | | [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) | |
136
- | `options` | `string` | Optionally | `assign_checkboxes` | | |
137
- | `password_field` | `string` | | | | |
138
- | `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. |
139
- | [`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. |
140
- | `text_area` | `text` | | | | |
141
- | `text_field` | `string` | | | | |
142
- | `number_field` | `integer` | | | | |
143
- | `trix_editor` | `text` | | | [Trix](https://github.com/basecamp/trix) | Basic HTML-powered formatting features and support for at-mentions amongst team members. |
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)
@@ -1,3 +1,3 @@
1
1
  module BulletTrain
2
- VERSION = "1.5.1"
2
+ VERSION = "1.5.2"
3
3
  end
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.1
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-02 00:00:00.000000000 Z
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