@@ -26,7 +26,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
26
26
$builder->addDependent('mainFood', ['meal'], function(DependentField $field, string $meal) {
27
27
// dynamically add choices based on the meal!
28
28
$choices = ['...'];
29
-
29
+
30
30
$field->add(ChoiceType::class, [
31
31
'placeholder' => null === $meal ? 'Select a meal first' : sprintf('What is for %s?', $meal->getReadable()),
32
32
'choices' => $choices,
@@ -65,7 +65,7 @@ use Symfonycasts\DynamicForms\DynamicFormBuilder;
65
65
public function buildForm(FormBuilderInterface $builder, array $options): void
66
66
{
67
67
$builder = new DynamicFormBuilder($builder);
68
-
68
+
69
69
// ...
70
70
}
71
71
```
@@ -136,7 +136,7 @@ if it's conditionally added:
136
136
{% if form.badRatingNotes is defined %}
137
137
{{ form_row(form.badRatingNotes) }}
138
138
{% endif %}
139
-
139
+
140
140
<button>Send Feedback</button>
141
141
{{ form_end(form) }}
142
142
```
@@ -153,9 +153,114 @@ This library doesn't handle this for you, but here are the 2 main options:
153
153
This is the easiest method: by rendering your form inside a live component,
154
154
it will automatically re-render when the form changes.
155
155
156
- ### B) Write custom JavaScript
156
+ ### B) Use [ Symfony UX Turbo] ( https://symfony.com/bundles/ux-turbo/current/index.html#decomposing-complex-pages-with-turbo-frames )
157
+
158
+ If you are already using Symfony UX Turbo on your website, you can have a dynamic form running quickly without any JavaScript.
159
+
160
+ Or you may want to install Symfony UX Turbo, [ check out the documentation] ( https://symfony.com/bundles/ux-turbo/current/index.html#installation ) .
161
+
162
+ > [ !NOTE]
163
+ > You only need to have Turbo Frame, you can disable Turbo Drive if you do not use it, or do not want to use it.
164
+ > ie: ` Turbo.session.drive = false; `
165
+
166
+ Simply add a ` <turbo-frame> ` around your form:
167
+
168
+ ``` twig
169
+ <turbo-frame id="rating-form">
170
+ {{ form(form) }}
171
+ </turbo-frame>
172
+ ```
173
+
174
+ From here you need two small changes:
175
+
176
+ First, in your form type:
177
+ - You need to add an attribute on the choice field, so it auto-submits the form when changed (may need to be adapted to your own form if more complex)
178
+ - Add a submit button, so in the controller you can differenciate from an auto-submit versus a user action
179
+
180
+
181
+ ``` diff
182
+ // src/Form/FeedbackForm.php
183
+
184
+ // ...
185
+
186
+ class FeedbackForm extends AbstractType
187
+ {
188
+ public function buildForm(FormBuilderInterface $builder, array $options)
189
+ {
190
+ $builder = new DynamicFormBuilder($builder);
191
+
192
+ $builder->add('rating', ChoiceType::class, [
193
+ 'choices' => [
194
+ 'Select a rating' => null,
195
+ 'Great' => 5,
196
+ 'Good' => 4,
197
+ 'Okay' => 3,
198
+ 'Bad' => 2,
199
+ 'Terrible' => 1
200
+ ],
201
+ + // This will allow the form to auto-submit on value change
202
+ + 'attr' => ['onchange' => 'this.form.submit()'],
203
+ ]);
204
+ + // This will allow to differenciate between a user submition and an auto-submit
205
+ + $builder->add('submit', SubmitType::class, [
206
+ + 'attr' => ['value' => 'submit'], // Needed for Turbo
207
+ + ]);
208
+
209
+ $builder->addDependent('badRatingNotes', 'rating', function(DependentField $field, ?int $rating) {
210
+ if (null === $rating || $rating >= 3) {
211
+ return; // field not needed
212
+ }
213
+
214
+ $field->add(TextareaType::class, [
215
+ 'label' => 'What went wrong?',
216
+ 'attr' => ['rows' => 3],
217
+ 'help' => sprintf('Because you gave a %d rating, we\'d love to know what went wrong.', $rating),
218
+ ]);
219
+ });
220
+ }
221
+ }
222
+ ```
223
+
224
+ Second, in your controller:
225
+ - Specify the action on your form, [ this is needed for Turbo Frame] ( https://symfony.com/bundles/ux-turbo/current/index.html#3-form-response-code-changes )
226
+ - Handle the auto-submit by checking if the button has been clicked
227
+
228
+ ``` diff
229
+ // src/Controller/FeedbackController.php
230
+
231
+ #[Route('/feedback', name: 'feedback')]
232
+ public function feedback(Request $request): Response
233
+ {
234
+ //...
235
+
236
+ - $feedbackForm = $this->createForm(FeedbackForm::class);
237
+ + $feedbackForm = $this->createForm(FeedbackForm::class, options: [
238
+ + // This is needed by Turbo Frame, it is not specific to Dependent Symfony Form Fields
239
+ + 'action' => $this->generateUrl('feedback'),
240
+ + ]);
241
+ $feedbackForm->handleRequest($request);
242
+ if ($feedbackForm->isSubmitted() && $feedbackForm->isValid()) {
243
+
244
+ + /** @var SubmitButton $submitButton */
245
+ + $submitButton = $feedbackForm->get('submit');
246
+ + if (!$submitButton->isClicked()) {
247
+ + return $this->render('feedback.html.twig', ['feedbackForm' => $feedbackForm]);
248
+ + }
249
+
250
+ // Your code here
251
+ // ...
252
+
253
+ return $this->redirectToRoute('home');
254
+ }
255
+
256
+ return $this->render('feedback.html.twig', ['feedbackForm' => $feedbackForm]);
257
+ }
258
+
259
+ ```
260
+
261
+ ### C) Write custom JavaScript
157
262
158
- If you're not using Live Components, you'll need to write some custom
263
+ If you're not using Live Components, nor Turbo Frames, you'll need to write some custom
159
264
JavaScript to listen to the ` change ` event on the ` rating ` field and then
160
265
make an AJAX call to re-render the form. The AJAX call should submit the
161
266
form to its usual endpoint (or any endpoint that will submit the form), take
0 commit comments