Commit c32d551
committed
feature #40430 [Form] Add "form_attr" FormType option (cristoforocervino)
This PR was squashed before being merged into the 5.3-dev branch.
Discussion
----------
[Form] Add "form_attr" FormType option
| Q | A
| ------------- | ---
| Branch? | 5.x
| Bug fix? |no
| New feature? | yes
| Deprecations? | no
| Tickets | N/A
| License | MIT
| Doc PR | [#15108](symfony/symfony-docs#15108)
## What is this about
This PR add support for [`form` attribute](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fae-form) to Symfony Form ([browser compatibility](https://caniuse.com/form-attribute)).
The `form` attribute allows form elements to override their associated form (which is their nearest ancestor form element by default). This is extremely useful to solve **nested form problem** and allows **form children** to be **rendered outside form tag** while still working as expected.
## New "form_attr" FormType option
#### form_attr
**type**: `bool` or `string` **default**: `false`
If set to `true` on a **root form**, adds [`form` attribute](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fae-form) on every children with their root **form id**.
This allows you to render form children outside the form tag and avoid **nested form problem** in some situations while keeping the form working properly.
If set to `true` on a **child**, adds [`form` attribute](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fae-form) on it with its **root form id**.
This allows you to render **that child** outside the form tag and avoid **nested form problem** in some situations while keeping the form working properly.
If root form has no `id` (this may happen by create an *unnamed* form), you can set it to a `string` identifier to be used at `FormView` level to link children and root form anyway.
## Usage on Root Form Example
#### Form Type
Enable the feature by setting `form_attr` to `true` on the root form.
```php
use Symfony\Component\Form\Extension\Core\Type;
class ListFilterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('search', Type\SearchType::class)
->add('orderBy', Type\ChoiceType::class, [
'choices' => [
// ...
],
])
->add('perPage', Type\ChoiceType::class, [
'choices' => [
// ...
],
])
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefault('form_attr', true); // <--- Set this to true
}
}
```
#### Twig
The following Twig template **works properly** even if form children are **outside** their form tag ([browser compatibility](https://caniuse.com/form-attribute)).
```twig
<div class="header-filters">
{{ form_errors(form) }}
{{ form_row(form.search) }} {# has attribute form="list_filter" #}
{{ form_row(form.orderBy) }} {# has attribute form="list_filter" #}
</div>
<!-- -->
<!-- Some other HTML content, like a table or even another Symfony form -->
<!-- -->
<div class="footer-filters">
{{ form_row(form.perPage) }} {# has attribute form="list_filter" #}
</div>
{{ form_start(form) }} {# id="list_filter" #}
{{ form_end(form) }}
```
✅ Every form elements work properly even outside form tag.
## Usage on Form Child Example
Enable the feature by setting `form_attr` to `true` on selected child.
```php
use Symfony\Component\Form\Extension\Core\Type;
class ListFilterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('search', Type\SearchType::class)
->add('orderBy', Type\ChoiceType::class, [
'choices' => [
// ...
],
])
->add('perPage', Type\ChoiceType::class, [
'form_attr' => true, // <--- Set this to true
'choices' => [
// ...
],
])
}
}
```
#### Twig
The following Twig template **works properly** even if `form.perPage` is **outside** form tag ([browser compatibility](https://caniuse.com/form-attribute)).
```twig
<div class="header-filters">
{{ form_start(form) }} {# id="list_filter" #}
{{ form_errors(form) }}
{{ form_row(form.search) }}
{{ form_row(form.orderBy) }}
{{ form_end(form, {'render_rest': false}) }}
</div>
<!-- -->
<!-- Some other HTML content, like a table or even another Symfony form -->
<!-- -->
<div class="footer-filters">
{{ form_row(form.perPage) }} {# has attribute form="list_filter" #}
</div>
```
✅ `form.perPage` element work properly even outside form tag.
Commits
-------
5f913cec74 [Form] Add "form_attr" FormType optionFile tree
6 files changed
+80
-2
lines changed- Extension/Core/Type
- Tests
- Extension/Core/Type
- Fixtures/Descriptor
6 files changed
+80
-2
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
99 | 109 | | |
100 | 110 | | |
101 | 111 | | |
| |||
210 | 220 | | |
211 | 221 | | |
212 | 222 | | |
| 223 | + | |
213 | 224 | | |
214 | 225 | | |
215 | 226 | | |
| |||
221 | 232 | | |
222 | 233 | | |
223 | 234 | | |
| 235 | + | |
224 | 236 | | |
225 | 237 | | |
226 | 238 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
774 | 775 | | |
775 | 776 | | |
776 | 777 | | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
777 | 839 | | |
778 | 840 | | |
779 | 841 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
| 43 | + | |
43 | 44 | | |
44 | 45 | | |
45 | 46 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
21 | | - | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
0 commit comments