Set an error on a "container" or a "details" element (the root of a widget, for example), and it won't be shown. Meanwhile, fieldsets work fine.

If the element has children (and it usually does), the children will (incorrectly, #2509268: Inline errors repeated on child elements in module uninstall form) show the errors, but as soon as we fix that, the error messages won't actually be seen. Swallowing errors sounds big enough to be critical, but feel free to knock it down to major.

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because certain errors get suppressed now
Issue priority Major because user can not see the error.
Disruption Zero disruption.

Comments

tim.plunkett’s picture

Priority: Critical » Major
Status: Active » Needs review
Issue tags: +Twig
StatusFileSize
new1.55 KB

I don't even know if this is valid HTML, but I borrowed the preprocess bit from template_preprocess_fieldset()

We're just swallowing the visual representation, the form will still fail validation correctly, so marking this major.

Not sure how to handle container

bojanz’s picture

StatusFileSize
new2.57 KB
new1.02 KB

We also need to modify the classy template, that's the one themes end up using. In the attached patch.

So, the container preprocess and template file can easily get the same treatment, but what makes container different is the fact that it's a generic theme/render element, not a form element. Is it weird for it to have errors in that case? Either it isn't, and we make the change, or it is, and we find a way to forbid setting errors on it, while communicating to people writing widgets and forms that they need to use a details element instead.

fabianx’s picture

#2: Why not put the errors to #prefix in that case to have them shown before the container element itself?

Containers are double-tricky as they are applied as #theme_wrappers on other elements always, so probably not even template_preprocess_container might help much here, as the element is already themed.

The patch here looks good for details.

Unless we find a good way (someone will need to do some experiments), I would suggest to split container off to another issue.

bojanz’s picture

Title: Inline errors not shown for details and container elements » Inline errors not shown for details elements

Okay, opened #2560467: Inline Errors not shown for container elements for the contaienr element.

bojanz’s picture

googletorp’s picture

Status: Needs review » Reviewed & tested by the community

For details this patch is good, let's get it in.

bojanz’s picture

Status: Reviewed & tested by the community » Needs work

We need to change the form-error-message class to form-item--error-message, to sync with #2501903: inline form errors classnames to follow namestandard.

Would also be great to figure out a test.

googletorp’s picture

Issue tags: +Needs tests
StatusFileSize
new2.57 KB
new510 bytes

The actual class name fix, was pretty simple, so let's just do that right away so we don't forget later on.

Will see if I can come up with a test for this as well.

strykaizer’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests +DUGBE0609
StatusFileSize
new1.87 KB
new4.44 KB

Attached you'll find a test only and patch with test + code from #8

The last submitted patch, 9: TEST_ONLY-inline_errors_not_shown-2512306-9.patch, failed testing.

Anonymous’s picture

Status: Needs review » Needs work

Looks great! I only found one nitpick:

+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupContainerForm.php
@@ -39,12 +39,26 @@ public function buildForm(array $form, FormStateInterface $form_state) {
+    if ($form_state->getValue('error_on_details') == True) {

s/True/TRUE

strykaizer’s picture

Status: Needs work » Needs review
StatusFileSize
new812 bytes
new4.44 KB

Thx for the review!

strykaizer’s picture

Issue summary: View changes
Anonymous’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

Looks good to me!

bojanz’s picture

Status: Reviewed & tested by the community » Needs work
/**
 * Builds a simple form to test the #group property on #type 'container'.
 */
class FormTestGroupContainerForm extends FormBase {

Looks like we're reusing an unrelated form? Why not add our own (+ route)? FormTestDetailsForm for example?

jeroent’s picture

Status: Needs work » Needs review
StatusFileSize
new5.35 KB
new3.25 KB

Created separate form and page for this test.

Patch attached.

bojanz’s picture

Thank you, JeroenT and StryKaizer. You are making my day.

+    $form['meta'] = [
+      '#type' => 'details',
+      '#title' => 'Group element',
+      '#open' => TRUE,
+      '#group' => 'container',
+    ];

The #group no longer means anything, so we can remove it. And the #title can be "Details element".

Other than that, this looks ready for an RTBC.

borisson_’s picture

StatusFileSize
new766 bytes
new5.32 KB

Attached patch fixes #17.

bojanz’s picture

Status: Needs review » Reviewed & tested by the community

We're good to go. Thanks, everyone.

If in the mood for more related work, the next one is: #2027059: Improve the documentation of WidgetBase::errorElement() for mapping violation property paths to form elements.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/system/templates/details.html.twig
@@ -20,6 +21,12 @@
+    <div>
+      {{ errors }}
+    </div>

Is the div necessary... putting on my morten hat? And then the if is not necessary either.

Also screenshots would be nice.

bojanz’s picture

Status: Needs work » Needs review

I added the div because fieldset.html.twig in the same folder has one:

  <div class="fieldset-wrapper">
    {% if errors %}
      <div>
        {{ errors }}
      </div>
    {% endif %}

Let's ask a themer.

mortendk’s picture

Status: Needs review » Reviewed & tested by the community

yes its correct that we have the same inside of fieldset.html.twig and in classy it have nice classes on it.
So it looks stupid with those div's for the sake ofthe divs - it was a part of the cleanup process on getting classy fixed.

we should probably kill those divs at some point as they have no meaing to core and only to classy, but i would suggest that its a followup in the ongoing divitis killing thats taken place, but thats for another issue (and we have one allready)
im pushing it back to rtbc

@alex can i get my hat back ;)

bojanz’s picture

Thank you, Morten.

Alex, I'll add a screenshot ASAP.

davidhernandez’s picture

The empty div is necessary because "errors" does not produce structured html content, at least not always, so you can edit up with just a string printed there without a paragraph tag or anything wrapping it.

bojanz’s picture

StatusFileSize
new259.59 KB
new273.94 KB

I used the provided form.

As I said, the error repeated on all elements is the result of a different bug (#2509268: Inline errors repeated on child elements in module uninstall form), and will actually be gone at one point.
The expected behavior is for the error to be shown on top of the form.

namespace Drupal\broken_form\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class BrokenForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'broken_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['address'] = [
      // The error set for $form['address'] shows as expected on #type = 'fieldset',
      // but not on #type => 'details'.
      '#type' => 'details',
      '#title' => 'Address',
      '#open' => TRUE,
      // #tree => TRUE is what triggers the "all children get the parent error"
      // bug.
      '#tree' => TRUE,
    ];
    $form['address']['country_code'] = [
      '#type' => 'select',
      '#title' => 'Country',
      '#options' => ['FR' => 'France', 'RS' => 'Serbia'],
    ];
    $form['address']['city'] = [
      '#type' => 'textfield',
      '#title' => 'City',
    ];
    $form['address']['postal_code'] = [
      '#type' => 'textfield',
      '#title' => 'Postal code',
    ];
    $form['address']['submit'] = [
      '#type' => 'submit',
      '#value' => 'Submit',
    ];

    return $form;
   }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $form_state->setError($form['address'], 'Everything is wrong.');
  }

  /**
   * {@inheritdoc}
   */
   public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message('Good job!');
   }
}

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Thanks @bojanz - we need to get all of this cleanup somehow done before rc :(

Nice work everyone. Committed 553e77c and pushed to 8.0.x. Thanks!

  • alexpott committed 553e77c on 8.0.x
    Issue #2512306 by StryKaizer, bojanz, googletorp, JeroenT, borisson_,...

Status: Fixed » Closed (fixed)

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