@@ -26,7 +26,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
2626 $builder->addDependent('mainFood', ['meal'], function(DependentField $field, string $meal) {
2727 // dynamically add choices based on the meal!
2828 $choices = ['...'];
29-
29+
3030 $field->add(ChoiceType::class, [
3131 'placeholder' => null === $meal ? 'Select a meal first' : sprintf('What is for %s?', $meal->getReadable()),
3232 'choices' => $choices,
@@ -65,7 +65,7 @@ use Symfonycasts\DynamicForms\DynamicFormBuilder;
6565public function buildForm(FormBuilderInterface $builder, array $options): void
6666{
6767 $builder = new DynamicFormBuilder($builder);
68-
68+
6969 // ...
7070}
7171```
@@ -136,7 +136,7 @@ if it's conditionally added:
136136 {% if form.badRatingNotes is defined %}
137137 {{ form_row(form.badRatingNotes) }}
138138 {% endif %}
139-
139+
140140 <button>Send Feedback</button>
141141{{ form_end(form) }}
142142```
@@ -153,9 +153,114 @@ This library doesn't handle this for you, but here are the 2 main options:
153153This is the easiest method: by rendering your form inside a live component,
154154it will automatically re-render when the form changes.
155155
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
157262
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
159264JavaScript to listen to the ` change ` event on the ` rating ` field and then
160265make an AJAX call to re-render the form. The AJAX call should submit the
161266form to its usual endpoint (or any endpoint that will submit the form), take
0 commit comments