Split from #2177469: Move node base widgets to the top level of the form
Currently, an $element that wants use the #group feature needs to make sure 'form_process_group' & 'form_pre_render_group' run as part of its processing & rendering.
So far, only 'container' types specify those in their hook_element_info() definition : fieldset, details, container
Patch linked above adds it to: datetime, textfield, textarea, checkbox as well, which sounds a bit arbitrary, and not too scalable.
Ideally #group should "just work" on any element type, not just on the ones that provision for it.
form_process_group() & form_pre_render_group() should just run on every sub-element in a form / render array as part of the default process / render stack.
No biggie for form_pre_render_group(), it's an early opt-out if $element['#group'] is not set. form_process_group() might need some refactoring to avoid a perf hit.
Problem / current behavior:
Drupal FAPI doesn't support visually grouping fields without affecting the field / form data structure as it requires nesting the fields, which is then reflected in the data structure:
$form['contact'] = [
'#type' => 'details',
'#title' => t('Contact details'),
'#open' => TRUE,
];
$form['contact']['name'] = [
'#title' => $this->t('Name'),
'#description' => $this->t('Enter your name.'),
'#type' => 'textfield',
'#default_value' => $this->options['name'],
];
Proposed solution:
Additonally, allow to group FAPI elements only visually, without affecting the field / form data structure. So that both ways are supported:
$form['contact'] = [
'#type' => 'details',
'#title' => t('Contact details'),
'#open' => TRUE,
];
$form['name'] = [
'#title' => $this->t('Name'),
'#description' => $this->t('Enter your name.'),
'#type' => 'textfield',
'#group' => 'contact',
'#default_value' => $this->options['name'],
];
TODO:
- Implement and write tests
- Update documentation from https://www.drupal.org/node/262758 (Drupal 6) for Drupal 8+
Comment | File | Size | Author |
---|---|---|---|
#34 | drupal-core_form-api_groups.patch | 8.12 KB | Carlitus |
#20 | 2190333-20.patch | 7.53 KB | ranjith_kumar_k_u |
#11 | 2190333_9-11_interdiff.txt | 1.77 KB | Pancho |
#11 | element_group_feature_2190333-11.patch | 7.57 KB | Pancho |
#9 | 2190333_7-9_interdiff.txt | 2.76 KB | Pancho |
Issue fork drupal-2190333
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #7
PanchoImportant, currently incomplete feature that allows decoupling visual form output from form value structure.
@tstoeckler in #2177469-45: Move node base widgets to the top level of the form:
@sun in #1856178-1: '#group' Form API property only works with <details> elements:
Currently, the feature is incomplete and inconsistent. There's no reason why '#group' works with textfields and a single checkbox, but not with selects or multiple checkboxes.
@sun in #2177469-41: Move node base widgets to the top level of the form:
We may refactor the logic directly into
FormBuilder
, deprecating the existing callbacks. But as a first step, let's add the callbacks to all elements inElementInfoManager
, then let's see which elements need special consideration (VerticalTabs for sure, but also Container after #2893586: Add #optional support to the Container render element.Here's a first patch. Let's see how it tests.
Comment #9
PanchoNot too bad.
Fixing the test failure.
Now we may also simplify
FieldLayoutBuilder::buildForm()
a bit, removing the #group processing code added in #2796173-39: Add experimental Field Layout module to allow entity view/form modes to switch between layouts.This patch landing should also be unblocking #2846393: [PP-1] Investigate alternative approaches to moving fields in FieldLayoutBuilder::buildView().
Furthermore, we may refactor many forms, as far as there are no BC concerns, replacing the value-reparenting with '#parents' by form-reparenting using '#group'. This may be a followup or rolled in. If we opted for rolling it in, we'd immediately get more test coverage for '#group'.
Comment #11
PanchoOkay, let's rewind and leave layout builder alone for now.
Comment #13
paper boyPatch is working well on a rather complex D 8.7.8 project.
Thanks a lot!
Comment #16
kawaljeet singh CreditAttribution: kawaljeet singh commentedNot working with Ajax callback, if we Replace select options using ajax callback.
Comment #19
GrimreaperPatch from comment 11 helped fix #3199414: #group property not working for select or some other setting types.
Thanks!
Comment #20
ranjith_kumar_k_u CreditAttribution: ranjith_kumar_k_u at Zyxware Technologies commentedRe-rolled # 11 for 9.4.
Comment #22
AnybodyJust ran into the same issue. The key point is, that quite often a way is required to group fields (and groups) without changing the field / form data structure.
While the nesting functionality works great, when you have full control over the code or even want nesting, everything is all right. But if form values are stored by a third party module or core, you may simply change the display, but not the data structure.
#group
seems to be a good approach for that case, where you don't want to change the nesting structure.Adding the "Needs documentation" tag, once this is available. Currently this only seems to be documented on the Drupal 6 documentation page: https://www.drupal.org/node/262758
I only found this blog article about using #group for this, while the documentation page only shows nesting examples.
#tree
doesn't seem to be helpful to preventExample case: Extend views StylePluginBase and add further fields. Use "details" field group to structure the additional settings, without breaking the form save logic. => Impossible (without manually massaging the nested values).
I wrote a blog post about that with examples: https://julian.pustkuchen.com/en/drupal-9-form-api-grouping-without-affe...
As this isn't really documented, what's the expected behavior and what's the plan for that in core?
Comment #23
AnybodyComment #24
AnybodyComment #25
AnybodyComment #28
jayhuskinsThe SystemMenuBlock gets around this issue with a
#process
value on the container elements that callsprocessMenuLevelParents
to remove the container from the form values.Comment #30
Carlitus CreditAttribution: Carlitus at Omitsis Consulting SL commentedTested and for the moment it works well.
Without a Checkbox, for example, works well with a details parent but not a Radios with a details parent.
With the #20 patch it works well with the Radios child.
I think getting this is a big step for Drupal, since as @Anybody says many times you can't modify the form structure but you do need to be able to group it.
Needed to make this patch: https://www.drupal.org/project/style_options/issues/3310055#comment-1519...
Comment #31
Anybody@Grimreaper and @Pancho any ideas how we can take this issue forward and perhaps get some frontend framework manager feedback on this?
I think before we make the next coding steps here, we should get some feedback from the core team, what they think about the key aspects?
Comment #32
Carlitus CreditAttribution: Carlitus at Omitsis Consulting SL commentedI've see that this doesn't work with managed_file and i don't know why.
It shows in the right position but when you select a file the ajax doesn't work well and disapears.
Comment #33
Carlitus CreditAttribution: Carlitus at Omitsis Consulting SL commentedNew patch to support managedFile and Ajax Callback.
I think this is not the best way to do it, but now al least works in my manual tests. I am sure that a person with more control of the core can do it in the most appropriate way.
I've see that the problem was when in the ajax callback to upload the file, the preRenderGroup was not needed and i've make a unset of the #groups in uploadAjaxCallback to skip this function.
Comment #34
Carlitus CreditAttribution: Carlitus at Omitsis Consulting SL commentedNew patch, the last one was wrong