Problem/Motivation

Current Behavior:
When building custom form with #radios only #attributes are passed to the individual #radio elements. We can still access the CvValidator 'required' by setting #attributes => ['required' => ''] however the error message will still appear next to the first radio in the set and display a misleading message like '{Option Label} is required'.

Expected Behavior:
When building custom form with #radios I can use #required and #required_error and the radio children will inherit the validator criteria. When submitting a form with a type #radios without selecting a radio, I expect the configured #required_error to appear beneath the of the wrapping fieldset like IFE.

Proposed resolution

Optional:
Leverage patch on https://www.drupal.org/project/drupal/issues/2951317 to allow #required to be passed to radio elements.
If you don't use the above patch, the CvValidator required plugin can still be triggered on radio via "#attributes => ['required' => ' ']"

For passing #required_error to radio elements:
Add conditional to Required.php that checks for #type => radio. If radio is not required and has parent #radios, run getRules on the parent, so we can access the #required_error.

To alter position of radios error message:
Add errorPlacement callback to cv.jquery.ife.js and insert beneath of the closest fieldset with data-drupal-selector that matches the errored radios data-drupal-selector without its radio index.

Remaining tasks

Add the patch.

API changes

// With a patch from https://www.drupal.org/project/drupal/issues/2951317
$form['radios'] = [
'#type' => 'radios',
'#title' => $this->t('How many Drupal sites have you built?'),
'#options' => $options_array,
'#required' => TRUE,
'#required_error' => 'Custom message',
];

// Without patch from https://www.drupal.org/project/drupal/issues/2951317.
$form['radios'] = [
'#type' => 'radios',
'#title' => $this->t('How many Drupal sites have you built?'),
'#options' => $options_array,
'#required' => TRUE, // continue to include so fieldset is rendered as required.
'#attributes' => [
'required' => ' ', // passed to #radio elements and caught by Required validator plugin.
],
'#required_error' => 'Custom message',
];

Comments

butlerbryanc created an issue. See original summary.

butlerbryanc’s picture

StatusFileSize
new2.06 KB
butlerbryanc’s picture

Issue summary: View changes
butlerbryanc’s picture

StatusFileSize
new2.07 KB
butlerbryanc’s picture

StatusFileSize
new2.09 KB

Update
Added isset check for #type before checking for radio to prevent errors when #type isn't set.

butlerbryanc’s picture

nikunjkotecha’s picture

Status: Active » Needs work

@butlerbryanc

Thanks for providing all the details in issue description and also for the patch.

Can you please add test for this?

themodularlab’s picture

StatusFileSize
new1.81 KB

I found that 3166606-5.patch didn't solve my issue at all. When i have a field set of multiple checkboxes and/or radios, the error message is still getting applied to the first radio/checkbox element and breaking the layout. So I made some minor adjustments. Possibly not the direction you want to take this, more might need more work, but it's at least a starting point or an alternative.

fenstrat’s picture

Just a heads up that if this is affecting you with webforms there is the webform_clientside_validation module (part of webform) that should fix this.

trevorbradley’s picture

@fenstrat just a heads up that webform_clientside_validation actually requires drupal/clientside_validation as a dependency in its info.yml file.

Something not note working with patch #8. Even with the patch applied, my validation message appears between the first radio button and the label. Investigating.

dystopianblue’s picture

Confirmed, #8 works. Make sure to enable `inline_form_errors` which I had forgot to do, causing it not to work initially.

pakmanlh’s picture

StatusFileSize
new1.95 KB
new533 bytes

I can confirm #8 works but sometimes the assumption of $complete_form['#type'] always existing can generate warning messages, for instance when you access `/admin/config/regional/language`when you have language module active.
I just added a check to mitigate this situation. Thanks!

andre.bonon’s picture

Hi, thanks everyone for your contribution to this issue.
I tried to fix the issue using your approach for webforms (clientside_validation + webform_clientside_validation + inline_form_errors), but the issue was still happening.
In my case, my theme extends from stable9 that doesn't add classes like "form-checkboxes", "form-radios", or "form-type-[type]" to the form elements, which are used in the webform_clientside_validation js selectors.
Stable9 adds "js-form-type-[type]" and forgets about the "form-type-[type]" as in the snippet below:

{%
  set classes = [
    'js-form-item',
    'form-item',
+        'form-type-' ~ type|clean_class, (THIS IS MISSING)
    'js-form-type-' ~ type|clean_class,
    'form-item-' ~ name|clean_class,
    'js-form-item-' ~ name|clean_class,
    title_display not in ['after', 'before'] ? 'form-no-label',
    disabled == 'disabled' ? 'form-disabled',
    errors ? 'form-item--error',
  ]
%}

I fixed the placement issue by overriding the form-element.html.twig and adding the code above. For the fieldset.html.twig, I added the following:

{%
  set classes = [
  'js-form-item',
  'form-item',
  'js-form-wrapper',
  'form-wrapper',
+  'form-' ~ element['#type'] (THIS IS MISSING)
]
andre.bonon’s picture

I reported this core bug https://www.drupal.org/project/drupal/issues/3380021, so it might avoid issues with themes based on stable9.

andre.bonon’s picture

igorbiki’s picture

Solution/patch #12 works for me. Both radios and checkboxes (as webforms elements) display error messages beneath all options.

nikunjkotecha’s picture

Version: 8.x-1.2 » 4.0.x-dev

Thanks everyone, I would really appreciate if we can have some tests added to the patch.

I am trying to reproduce and confirm the fix and improve the solution (make it generic and work even without inline_form_errors module), I have got radios working but not able to make normal required validation work for checkboxes.