Problem/Motivation

When a part of the component form is loaded by AJAX after a select change, its checkboxes that should be checked by default arrive unchecked. Nobody touched them, and saving stores false.

Four ways to see it:

- A source with a checkbox setting that defaults to true. Switch the source of a prop to it: the checkbox is unchecked.
- A component prop with "default: true" in its definition. Pick the component in a field formatter, in a view field, or as a component inside a slot: the prop's checkbox is unchecked.
- The Block source. Add it to a slot and pick "Site branding": "Site logo", "Site name" and "Site slogan" are unchecked, although the block checks them by default.
- The Field formatter source. Pick any formatter, then the "Label" formatter: "Link label to the referenced entity" is unchecked, although the formatter links by default.

The same checkbox shows its default when its form is part of the page load, for instance the props of a block whose component is fixed. Only a form loaded by a source, component, block or formatter select change is affected: adding a source to a slot is fine.

Steps to reproduce

1. Place the block of any component having a slot.
2. In the slot, add the "Block" source, then pick "Site branding".
3. "Site logo", "Site name" and "Site slogan" are unchecked. Save the block: the three settings are stored as false and the branding block renders empty.

Same with a custom source:

1. Write a source with a setting "loud" defaulting to TRUE and a checkbox for it in settingsForm().
2. On any string prop, switch the source to it.
3. The checkbox is unchecked. Save: the setting is stored as false.

Why it happens

Core processes an AJAX request twice: once with the submitted values, then a rebuild that is sent back to the browser. Our forms build the newly selected sub-form already in the first pass, from the request input. In that pass core writes an empty value into the input for every element it does not find in the request, and the rebuild takes that empty value for "unchecked" instead of using the default. Core expects a new sub-form to appear only in the rebuild, which our forms cannot do since a normal save has a single pass and needs the input.

The request looks exactly the same for a new checkbox and for a checkbox the user has unchecked: nothing is sent in both cases. Only the select that triggered the request tells them apart.

Proposed resolution

The selects that load a new sub-form next to them (source, component, block plugin, formatter type) declare it with a form property. In the first pass, the empty entries core wrote for the elements next to such a select are dropped from the input, so the rebuild applies their defaults. Real values are kept and elements elsewhere in the form are not touched: a checkbox the user unchecked stays unchecked.

Tests: the test component's "boolean_with_default_true" and "boolean_with_default_false" props get real defaults, a test source with a true and a false default setting is added, and the block and field formatter Playwright specs check the defaults on arrival, after save and reopen, and in the rendered page.

Command icon 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

just_like_good_vibes created an issue. See original summary.

just_like_good_vibes’s picture

Assigned: just_like_good_vibes » Unassigned
Status: Active » Needs review
pdureau’s picture

Assigned: Unassigned » pdureau
pdureau’s picture

Assigned: pdureau » just_like_good_vibes
Status: Needs review » Reviewed & tested by the community

I didn't test in my local environment, but the MR looks OK

just_like_good_vibes’s picture

Assigned: just_like_good_vibes » Unassigned
Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.