Problem/Motivation

This is a follow up of #2828092: Inline Form Errors not compatible with Quick Edit .

In certain cases (like what Quick Edit does with forms) we want modules to have the possibility to disable Inline Form Errors (IFE) completely.

We shouldn't encourage maintainers to do so because we don't want bad ux and a11y, but in cases those issues are covered they do need the possibility to create their own form interaction UI.

Proposed resolution

add a form property which can be used to disable IFE $form['#disable_inline_form_errors'] = TRUE;

Remaining tasks

Write a CR (https://www.drupal.org/node/2899118)

User interface changes

N/A

API changes

API addition: a new FAPI property to disable inline form errors.

Data model changes

N/A

CommentFileSizeAuthor
#71 Selection_215.png36.91 KBberdir
#65 2856950-64.patch7.92 KBdmsmidt
#64 interdiff-2856950-59-64.txt8.88 KBdmsmidt
#59 2856950-IFE-59.patch13.1 KBtim.plunkett
#52 2856950-IFE-52.patch13.74 KBtim.plunkett
#52 2856950-IFE-52-interdiff.txt3.2 KBtim.plunkett
#46 2856950-IFE-46-interdiff.txt14.34 KBtim.plunkett
#46 2856950-IFE-46.patch13.49 KBtim.plunkett
#43 interdiff-2856950-40-43.txt296 bytesandrewmacpherson
#43 2856950-43.patch13.25 KBandrewmacpherson
#40 2856950-40.patch13.2 KBdmsmidt
#40 interdiff-2856950-37-40.txt3.13 KBdmsmidt
#37 2856950-37.patch13.29 KBdmsmidt
#37 interdiff-2856950-30-37.txt718 bytesdmsmidt
#30 interdiff-2856950-29-30.txt2.94 KBmarcvangend
#30 2856950-30.patch13.35 KBmarcvangend
#29 interdiff-2856950-27-29.txt10.88 KBmarcvangend
#29 2856950-29.patch13.03 KBmarcvangend
#27 interdiff-2856950-26-27.txt1.98 KBmarcvangend
#27 2856950-27.patch12.88 KBmarcvangend
#26 interdiff-2856950-20-26.txt2.95 KBmarcvangend
#26 2856950-26.patch13.14 KBmarcvangend
#20 2856950-20.patch12.69 KBlendude
#20 interdiff-2856950-19-20.txt6.76 KBlendude
#19 interdiff-2856950-17-19.txt2.52 KBdmsmidt
#19 2856950-19.patch8.13 KBdmsmidt
#17 interdiff-2856950-9-17.txt2.85 KBdmsmidt
#17 2856950-17.patch6.29 KBdmsmidt
#4 2856950-4.patch2.05 KBdmsmidt
#6 2856950-6.patch3.33 KBdmsmidt
#6 interdiff-2856950-4-6.txt1.28 KBdmsmidt
#9 interdiff.txt1.12 KBtameeshb
#9 2856950-9.patch3.33 KBtameeshb
#13 2856950-13_IFE-module-enabled_new-per-form-disable-ife-property.png336.99 KBandrewmacpherson
#13 2856950-13_IFE-module-enabled.png301.55 KBandrewmacpherson
#13 2856950-13_IFE-module-disabled.png270.04 KBandrewmacpherson

Comments

dmsmidt created an issue. See original summary.

dmsmidt’s picture

Issue summary: View changes
dmsmidt’s picture

Assigned: Unassigned » dmsmidt
Issue tags: +DevDaysSeville
dmsmidt’s picture

Status: Active » Needs review
StatusFileSize
new2.05 KB

Since I had no feedback so far I went ahead and created a prototype for the solution that had most of the votes (new $form property).
This patch allows a developer to exclude inline form errors (at form definition time and when using a form_alter).

The test created in #2828092: Inline Form Errors not compatible with Quick Edit already tests if this works. But I guess we may need a standalone unit test for this?

Status: Needs review » Needs work

The last submitted patch, 4: 2856950-4.patch, failed testing.

dmsmidt’s picture

Status: Needs work » Needs review
StatusFileSize
new3.33 KB
new1.28 KB

And with test fix.

tim.plunkett’s picture

In #2828092-58: Inline Form Errors not compatible with Quick Edit catch said

Was going to suggest a .yml file with a list of form IDs, then we just check in_array()/isset() rather than hard-coding knowledge of other module's forms here. Or a custom $form['#property'] to check would be more lightweight

It seems like he also supports this approach. As do I.

  1. +++ b/core/modules/inline_form_errors/tests/src/Unit/FormErrorHandlerTest.php
    @@ -140,12 +140,12 @@ public function testSetElementErrorsFromFormState() {
    +   * Test that opting out for inline form errors works.
    

    opting out *of*

  2. +++ b/core/modules/quickedit/src/Form/QuickEditFieldForm.php
    @@ -114,6 +114,10 @@ public function buildForm(array $form, FormStateInterface $form_state, EntityInt
    +    // Use the non inline form error display for Quick Edit forms, because in
    

    non-inline

Otherwise I think this is RTBC-worthy

dmsmidt’s picture

Assigned: dmsmidt » Unassigned
Status: Needs review » Needs work
Issue tags: +Novice

@tim Thanks for the review. Those nits seem easy enough to fix.

tameeshb’s picture

Status: Needs work » Needs review
StatusFileSize
new1.12 KB
new3.33 KB
andrewmacpherson’s picture

Status: Needs review » Reviewed & tested by the community

The patch in #9 corrects the points from #7. I confirmed the interdiff after downloading both patches form # and #9.

th_tushar’s picture

Looks good. +1

dmsmidt’s picture

Status: Reviewed & tested by the community » Needs review

Did anyone actually test this while altering a form for example?
I love that you guys RTBC this of course, but please leave some testing feedback.

andrewmacpherson’s picture

Status: Needs review » Needs work
StatusFileSize
new270.04 KB
new301.55 KB
new336.99 KB

It doesn't work completely yet for forms in general.

I updated @dmsmidt's errorstyle module so that it will optionally use the proposed new $form[#disable_inline_form_errors'] FAPI property.

See the GitHub pull request: Support #disable_inline_form_errors FAPI property

I tested the patch from #9 using the errorstyle module, in 3 ways (screenshots attached):

  • With Inline Form Errors module disabled.
  • With Inline Form Errors module enabled.
  • With Inline Form Errors module enabled, and the new $form[#disable_inline_form_errors'] property set.

The patch in #9 only affects the error message at the top of the page, via Drupal\inline_form_errors\FormErrorHandler::Drupal\inline_form_errors(). When Inline Form Errors module is enabled, and $form[#disable_inline_form_errors'] is applied to the whole form, we get the normal core error message at the top of the page (i.e. a long list without links), but we still see inline error messages for each individual element.

I think we need to test for $form[#disable_inline_form_errors'] during form element preprocessing, in the _inline_form_errors_set_errors() helper function. I poked around dpm($variables) but couldn't find a quick way to read the parent form property.

andrewmacpherson’s picture

Aside: the alternate proposal...

- @catch: Keep a .yml file with form_ids that should be excluded

... would make a good contrib module! Just a settings form with a big text area, listing one form ID per line. Then set #disable_inline_form_errors with hook_form_alter().

andrewmacpherson’s picture

Issue tags: -Novice

Removing novice tag, that was for the typos in #7

dmsmidt’s picture

Issue tags: +Needs tests

@andrewmacpherson, thanks for actually testing thoroughly!
Adding 'needs tests' again in order to cover the 'inline messages' part.

dmsmidt’s picture

Status: Needs work » Needs review
StatusFileSize
new6.29 KB
new2.85 KB

Alright here is a new version that should hide all inline error messages.
Still tests needed.

dmsmidt’s picture

Assigned: Unassigned » dmsmidt

Writing tests

dmsmidt’s picture

Assigned: dmsmidt » Unassigned
StatusFileSize
new8.13 KB
new2.52 KB

Improved the tests. Now also checks for form elements (next to the summary).

lendude’s picture

StatusFileSize
new6.76 KB
new12.69 KB

@dmsmidt as promised, the underscore prefixed function moved out of the .module file to a service, with some test coverage.

dmsmidt’s picture

Thanks @lendude, this is indeed much more in line with D8's OOP structure, and makes it much more extendable and better documented.

tedbow’s picture

Status: Needs review » Needs work

Looking good so far!

  1. +++ b/core/modules/inline_form_errors/inline_form_errors.module
    @@ -49,6 +51,43 @@ function inline_form_errors_preprocess_datetime_wrapper(&$variables) {
    +  // Add a processor for form elements and pseudo form elements.
    ...
    +  foreach ($info as $element_type => $element_info) {
    +    if ($determiner->isFormElement($element_type)) {
    ...
    +    }
    +  }
    ...
    +function inline_form_errors_process_form_element(array &$element, FormStateInterface $form_state, array &$complete_form) {
    

    I am all for moving code out of the module into a service but why not make service in encapsulate more.

    You could use a service that does more maybe FormElementProcessor.

    Then this hook could just be 1 line.

    \Drupal::service('inline_form_errors.form_element_processor')->attachProcessCallback($info);

    Then in that method instead of setting #process to again a method in .module I think it would be ok to set the callback to method on the class. If it is ok practice to have a public static method on service. Like so:

    $info[$element_type]['#process'][] = [static::class, 'proccesElement'];

  2. +++ b/core/modules/inline_form_errors/src/FormErrorHandler.php
    @@ -47,15 +47,18 @@ public function __construct(TranslationInterface $string_translation, LinkGenera
    +   * To disable inline form errors for a complete form set the
    +   * '$form[#disable_inline_form_errors]' property to TRUE. This should only be
    +   * done when another appropriate accessibility strategy is in place.
    

    Should we be explicit the $form must be the top level of the form?

  3. +++ b/core/modules/inline_form_errors/tests/src/Kernel/FormElementInlineErrorTest.php
    @@ -0,0 +1,49 @@
    +  /**
    +   * Modules to enable.
    +   *
    +   * @var array
    +   */
    

    Can just use {@inheritdoc}

  4. +++ b/core/modules/inline_form_errors/tests/src/Kernel/FormElementInlineErrorTest.php
    @@ -0,0 +1,49 @@
    +    $this->assertArraySubset(['#error_no_message' => TRUE], $form['test']);
    

    Could use a message or comment to tell why this proves it works.

dmsmidt’s picture

Issue tags: +sprint
sutharsan’s picture

+++ b/core/modules/inline_form_errors/src/FormElementDeterminer.php
@@ -0,0 +1,78 @@
+    if (!empty($element_definitions[$element_type])) {
+      $element = $this->elementInfoManager->createInstance($element_type);
+      return $element instanceof FormElementInterface;
+    }

This requires the form elements to be instantiated. Using class_implements() will be more performant.

I've tested the below code. It takes (approx.) only 30% of the execution time of the original code.

$interfaces = class_implements($element_definitions[$element_type]['class']);
return isset($interfaces['Drupal\Core\Render\Element\FormElementInterface']);
marcvangend’s picture

I'm working on this in the a11y sprint @Synetic.

marcvangend’s picture

StatusFileSize
new13.14 KB
new2.95 KB

Let's start with the low-hanging fruit: #22 points 2, 3 & 4, and one more documentation improvement in \Drupal\Tests\inline_form_errors\Unit\FormElementDeterminerTest::testIsFormElement().

marcvangend’s picture

Status: Needs work » Needs review
StatusFileSize
new12.88 KB
new1.98 KB

Here's another patch which implements @Sutharsan's performance improvement and updates FormElementDeterminerTest to work with the class_implements method.

marcvangend’s picture

marcvangend’s picture

StatusFileSize
new13.03 KB
new10.88 KB

As discussed with @Lendude and @dmsmidt at the code sprint, this patch changes the name of FormElementDeterminer to the more meaningful SupportedRenderElementHelper. It also improves some inline docs and cleans up some redundant use statements. Unfortunately interdiffs aren't very readable for changes like this.

marcvangend’s picture

StatusFileSize
new13.35 KB
new2.94 KB

This is probably my last patch on this issue for today, related to #22 number 1. The patch moves inline_form_errors_process_form_element() to a static method in a helper class \Drupal\inline_form_errors\FormElementProcessor. The FormElementProcessor class is not a service, because there is no need for it to be instantiated or to be present in the service container.

lendude’s picture

Status: Needs review » Reviewed & tested by the community

All feedback from #22 has been addressed, this looks really nice now.

dmsmidt’s picture

Really nice work today, thanks!

lauriii’s picture

I did read through the code and it didn't raise questions on my side. I also noticed that we've added test coverage so I removed the tag. I will let one of the other maintainers make the final call on this. Before one of the other maintainers will take a look at this, I think we totally should still create a small change record for this addition.

I've also updated the issue credits.

Thanks everyone!

gábor hojtsy’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/inline_form_errors/src/FormErrorHandler.php
    @@ -47,15 +47,23 @@ public function __construct(TranslationInterface $string_translation, LinkGenera
    +   * #disable_inline_form_errors property to TRUE on the top level of the $form
    +   * array, ie:
    +   * @code
    +   * $form['#disable_inline_form_errors property'] = TRUE;
    

    Code example is incorrect.

  2. +++ b/core/modules/inline_form_errors/src/SupportedRenderElementHelper.php
    @@ -0,0 +1,79 @@
    +  public function supportsInlineFormErrors($element_type) {
    +    return in_array($element_type, $this->pseudoFormElements) || $this->elementInstanceOfFormElementInterface($element_type);
    +  }
    

    Is there a use case to alter this? Would swapping the service serve that use case or would multiple sources want to alter it (if there is a use case to alter it in any case)?

dmsmidt’s picture

@Gábor #34.2: If contrib adds RenderElements that need to show Inline Form Errors while not implementing FormElementInterface they would need to be able to alter this. However that seems like a very small use case.
Let's create a follow up to somehow let those element type be listed in $this->pseudoFormElements. Maybe we should add an extra property to the annotations.

gábor hojtsy’s picture

@dmsmidt: great, we can definitely expand features later on if this implementation / API does not make further expansion without a BC break impossible / very hard. Not sure how would the expansion work, annotation additions would be backwards compatible I guess. Can you open that followup?

dmsmidt’s picture

Status: Needs work » Needs review
Related issues: +#2895882: Allow contrib modules to create Inline Form Errors supported RenderElements that are no Form Elements
StatusFileSize
new718 bytes
new13.29 KB
tim.plunkett’s picture

Mostly nits left:

  1. +++ b/core/modules/inline_form_errors/src/SupportedRenderElementHelper.php
    @@ -0,0 +1,79 @@
    +   * SupportedRenderElementHelper constructor.
    

    Constructs a new SuppportedRenderElementHelper.

  2. +++ b/core/modules/inline_form_errors/src/SupportedRenderElementHelper.php
    @@ -0,0 +1,79 @@
    +   * Determine if a render element type supports inline form errors.
    ...
    +   * Determine if a render element type implements FormElementInterface.
    

    Determines

  3. +++ b/core/modules/inline_form_errors/src/SupportedRenderElementHelper.php
    @@ -0,0 +1,79 @@
    +    $element_definitions = $this->elementInfoManager->getDefinitions();
    ...
    +    if (!empty($element_definitions[$element_type])) {
    

    Should use ->hasDefinition() and ->getDefinition()

  4. +++ b/core/modules/inline_form_errors/src/SupportedRenderElementHelper.php
    @@ -0,0 +1,79 @@
    +      return isset($interfaces['Drupal\Core\Render\Element\FormElementInterface']);
    

    FormElementInterface::class

  5. +++ b/core/modules/inline_form_errors/tests/src/Kernel/FormElementInlineErrorTest.php
    @@ -0,0 +1,50 @@
    +   * Test that form elements get the #error_no_message property when opting out
    

    Tests

dmsmidt’s picture

Assigned: Unassigned » dmsmidt
dmsmidt’s picture

Assigned: dmsmidt » Unassigned
StatusFileSize
new3.13 KB
new13.2 KB

#38: fixed. Also redid the short descriptions of some docblocks to fit on one line.

Status: Needs review » Needs work

The last submitted patch, 40: 2856950-40.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

marcvangend’s picture

Re. #34 - #37:
We had already identified that need during the sprint on July 2nd and I created a follow up for it in #28: #2891648: Allow hiding of inline form errors on non-form elements when it is disabled for the complete form.

We should close either that issue or #2895882: Allow contrib modules to create Inline Form Errors supported RenderElements that are no Form Elements as duplicate.

PS re. #34.1 Good catch, can't believe I missed that :-)

andrewmacpherson’s picture

StatusFileSize
new13.25 KB
new296 bytes

This fixes the missing empty line that automated code sniffer found.

I haven't figured out the test failure, but it's to do with the changes for #38.3

dmsmidt’s picture

Assigned: Unassigned » tim.plunkett

@andrew thanks, I discussed this with Tim Plunkett, he is working on fixing the tests.

tim.plunkett’s picture

  1. +++ b/core/modules/inline_form_errors/inline_form_errors.services.yml
    @@ -0,0 +1,4 @@
    +    class: Drupal\inline_form_errors\SupportedRenderElementHelper
    
    +++ b/core/modules/inline_form_errors/src/SupportedRenderElementHelper.php
    @@ -0,0 +1,77 @@
    +class SupportedRenderElementHelper {
    

    Usually "Helper" classes only contain static methods.

    Also, services should have interfaces provided

  2. +++ b/core/modules/inline_form_errors/src/FormErrorHandler.php
    @@ -47,15 +47,23 @@ public function __construct(TranslationInterface $string_translation, LinkGenera
    +   * array, ie:
    

    i.e.:

    (or don't use i.e.)

  3. +++ b/core/modules/inline_form_errors/src/SupportedRenderElementHelper.php
    @@ -0,0 +1,77 @@
    +   * @var \Drupal\Core\Render\ElementInfoManager
    ...
    +  public function __construct(ElementInfoManager $element_info_manager) {
    
    +++ b/core/modules/inline_form_errors/tests/src/Unit/SupportedRenderElementHelperTest.php
    @@ -0,0 +1,56 @@
    +    $element_info_manager = $this->getMockBuilder(ElementInfoManager::class)
    

    These should all be ElementInfoManagerInterface

  4. +++ b/core/modules/inline_form_errors/tests/src/Unit/SupportedRenderElementHelperTest.php
    @@ -0,0 +1,56 @@
    +      ->setConstructorArgs([
    +        $this->getMock(\Traversable::class),
    +        $this->getMock(CacheBackendInterface::class),
    +        $this->getMock(CacheTagsInvalidatorInterface::class),
    +        $this->getMock(ModuleHandlerInterface::class),
    +        $this->getMock(ThemeManagerInterface::class),
    +      ])
    +      ->setMethods(['getDefinitions', 'createInstance'])
    +      ->getMock();
    ...
    +    $element_info_manager->expects($this->any())
    +      ->method('getDefinitions')
    +      ->willReturn([
    

    Ideally these would be using Prophecy

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new13.49 KB
new14.34 KB

I don't think that allowing others to add more $pseudoFormElements is in scope for this issue. Plus, only one module per site could swap out the service, so a service isn't an appropriate solution.

This fixes my concerns from above.

The interdiff is bigger than patch, sorry.

tim.plunkett’s picture

The change to ElementInfoManagerInterface is a necessary part of this patch, but opened a separate issue in case it is deemed out of scope:
#2899082: ElementInfoManagerInterface must extend DiscoveryInterface

dmsmidt’s picture

I'm oké with the idea behind the rewrite. I didn't see anything strange on first glance. The patch is less sophisticated (less files and code in the .module file). I'll do a manual test later and check it a bit more in depth.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tim.plunkett’s picture

Version: 8.5.x-dev » 8.4.x-dev
Issue summary: View changes
dmsmidt’s picture

Assigned: tim.plunkett » Unassigned
Status: Needs review » Needs work

Manual tests confirm everything still works as expected. After thinking a bit more about it I still think not using services is oke, since we don't introduce logic that should be easily reusable by other modules.

Some nits/remarks:

  1. +++ b/core/modules/inline_form_errors/src/SupportedRenderElementHelper.php
    @@ -0,0 +1,126 @@
    +/**
    + * Provides a way to check if a render element type supports inline form errors.
    + */
    

    This is no longer correct since this class is now also responsible for adding the element process function and the processing it self.
    Maybe use: 'Provides functionality to determine and process supported render elements.'

  2. +++ b/core/modules/inline_form_errors/src/SupportedRenderElementHelper.php
    @@ -0,0 +1,126 @@
    + * Provides a way to check if a render element type supports inline form errors.
    ...
    +   * Determines if an element type supports inline form errors.
    ...
    +   *   which supports inline form errors, or FALSE otherwise.
    
    +++ b/core/modules/inline_form_errors/tests/src/Unit/FormErrorHandlerTest.php
    @@ -140,12 +140,9 @@ public function testSetElementErrorsFromFormState() {
    +   * Tests that opting out of inline form errors works.
    

    Since this refers to the module, 'inline form errors' should be with capital letters.

  3. +++ b/core/modules/inline_form_errors/tests/src/Unit/SupportedRenderElementHelperTest.php
    @@ -0,0 +1,65 @@
    +class SupportedRenderElementHelperTest extends UnitTestCase {
    ...
    +   * @covers ::supportsInlineFormErrors
    ...
    +  public function testSupportsInlineFormErrors($element_type, $definition, $expected) {
    

    Should we add a description and params for this? Or is it allowed to skip those in tests? I see mixed usage in core.

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new3.2 KB
new13.74 KB

@dmsmidt is working on the CR.

Addressed all 3 points, thanks!

dmsmidt’s picture

Issue summary: View changes

The changes of #52 cover my concerns.
Change record added: https://www.drupal.org/node/2899118.
This has my +1 for RTBC.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tedbow’s picture

Isn't $form['#disable_inline_form_errors'] = TRUE; an API shouldn't we have a inline_form_errors.api.php Otherwise it seems like it would be really hard to figure this out.

tedbow’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs change record

I guess we don't have don't have a practice for making *.api.php files for # properties.

It is documented here https://www.drupal.org/docs/8/core/modules/inline-form-errors/inline-for...

Looks great! RTBC 🏅

xjm’s picture

Status: Reviewed & tested by the community » Needs work

Some feedback on the change record. It says:

It is now possible to disable Inline Form Errors (IFE) for a specific form when the module is enabled. This is an addition to the Form API.

Isn't it more "for a specific form or any form element"? Actually, now that I'm looking at it, the keys are #disable_inline_form_errors and #error_no_message. That's a bit confusing.

I also agree with @tedbow's first instinct that this needs to be documented in the API documentation. The handbook page is good to have, but it's not API documentation. We've definitely gone through a lot of different best practices for where form elements and properties should be documented, and it's probably not a *.api.php; I can't remember right now though how we document them normally.

tim.plunkett’s picture

This was to be the stop-gap solution. The added property ONLY works when used on the top-level $form element.
#2891648: Allow hiding of inline form errors on non-form elements when it is disabled for the complete form is the issue for individual elements. The property to be added in that issue would be documented directly on \Drupal\Core\Render\Element\RenderElement.

The only other properties that exclusive to the top-level $form element I can think of are internal-only: #cache_token, #build_id, #action
They are not documented anywhere.

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new13.1 KB
xjm’s picture

Hmm, what is #2891648: Allow hiding of inline form errors on non-form elements when it is disabled for the complete form postponed on? This doesn't seem like it's all that hotfix-y and the other doesn't really propose anything particular yet.

The comment from @catch that spawned this issue is:

I think it's OK for the patch to go in like this, but inline_form_errors should eventually be not-a-module whereas quickedit is going to stay one. So I think we need a follow-up to remove the hard-coded dependency.

Was going to suggest a .yml file with a list of form IDs, then we just check in_array()/isset() rather than hard-coding knowledge of other module's forms here. Or a custom $form['#property'] to check would be more lightweight.

#2848319: Find a way to make it easier to hide Inline Form Error messages on child elements was suggested as the issue for that, but not sure that's about this issue at all? Looks like it was talking about other bugs which are already fixed, might just need re-scoping though.

Might just need an issue summary update but it's not clear to me what the next steps are here.

(From #2828092-58: Inline Form Errors not compatible with Quick Edit .) So I guess I was imagining this issue's scope to be somewhat wider than it actually is. (For some reason I was thinking the #error_no_message thing was IFE, but it's just generic FAPI that's also used on a few datetime things.) However, I'm wondering what the value of this is? I could see disabling IFE with a particular module, but an API (a FAPI key, no less) to disable IFE for just a single form seems pretty edgecase to me.

I did commit #2899082: ElementInfoManagerInterface must extend DiscoveryInterface separately (thanks for the separate issue; I was about to push back on that change but then the separate issue answered my questions).

In terms of documenting this bit, I guess @tedbow's inline_form_errors.api.php suggestion is as good as any, but I do think we need something more than a handbook page.

dmsmidt’s picture

First of all, this issue was indeed spawned from the Quick Edit Quick Fix, the whole idea was just to make disabling IFE possible without specific hacks for certain forms of certain modules from within IFE module. This patch allows to do so for any form with a form_alter or within the form definition directly.

Disabling IFE for a complete module doesn't sound like a solid idea. What if the module adds different kind of forms? Say one form for an advanced use case on the visitor facing part of the site and also some admin forms?

I'm glad this issue is for edge cases, we want to have all forms accessible without a hassle. However we can't ignore that there are edge cases and I don't want to limit experimental UI's. Currently we use this only for Quick Edit in core, but we shouldn't limit contrib and allow it to come up with advanced UI's. Also when #77245: Provide a common API for displaying JavaScript messages lands we can expect more advanced UI's that handle their own error reporting.

A simple use case I could imagine that doesn't need IFE is a form with a single input, like search. Having a summary might be a bit strange when you can just print a singe error near the element.

I renamed #2891648: Allow hiding of inline form errors on non-form elements when it is disabled for the complete form, this follow up is only for non-form elements that are used in a form context (like wrappers), it would only be for contrib and it is postponed on this issue. We can just see if any contrib module needs it at all...

#error_no_message doesn't have anything to do with this issue directly, it does not stop displaying the summary, and needs to be set for all elements individually. And yes that we reuse all kinds of properties of Form API becomes messy. Another example is that we now store error messages in a property that was ment to only indicate that the element should be highlighted as having an error, which causes a lot of problems with compound fields and bubbling of errors.

I'll think about API documentation, I was cracking my brain on how to do that for form properties as well..

xjm’s picture

So, the summary for the other issue is:

I'm creating this issue as 'Postponed' because #2856950: Add a possibility to disable inline form errors for a complete form should be possible for 8.4.0, but it's probably too late to be changing render element annotations now.

That's different from the scope in the changed title, though.

My question is, if this issue was just intended as a "stopgap" that we could land by 8.4.0, and we had a more complete fix in mind, how about we instead just go for the complete fix? What would it look like? As currently titled, #2891648: Allow hiding of inline form errors on non-form elements when it is disabled for the complete form is unrelated to the scope of this issue, but do they have some underlying shared solution?

dmsmidt’s picture

@xjm, I'll try to clarify. I worked with @marcvangend (creator of the follow up) on this issue during a sprint.

This issue is not at all ment as a "stopgap" it is the pretty solution to the current workaround for Quick Edit. And module developers could already benefit from this even without the follow up. I renamed it again and updated the summary #2891648: Allow hiding of inline form errors on non-form elements when it is disabled for the complete form.

We could potentially just get rid of this list of 'supported render elements', because we don't use it to actually show inline form errors. If the template of an element prints the errors, showing inline form errors is supported out of the box. This list of render elements is actually a list of render elements that can be stopped from showing inline form errors by opting out the complete form in one go (single property on $form).
By getting rid of this list (and the type checks) we would set #error_no_message on any render element even if they couldn't display inline errors anyhow. Which doesn't break anything.

dmsmidt’s picture

StatusFileSize
new8.88 KB

Alright, this patch is a very simplified version which gets rid of all 'supports' rhetoric, it's confusing.
Using this version of the patch all render elements are handled equally, contrib doesn't need to declare anything for new elements (win!).
Since element processing (#process) is done in the FormBuilder, processing of elements is only done for render elements in forms, the impact of not discriminating between types is thus not so big.

If this approach gets in, sorry guys for the code round trip, your help is much appreciated!

dmsmidt’s picture

StatusFileSize
new7.92 KB
gagarine’s picture

Issue tags: -UX +Usability

Usability is preferred over UX, D7UX, etc. See https://www.drupal.org/issue-tags/topic

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

This looks great! And there are no remaining tasks.

larowlan’s picture

+++ b/core/modules/inline_form_errors/src/FormErrorHandler.php
@@ -47,15 +47,23 @@ public function __construct(TranslationInterface $string_translation, LinkGenera
+   * $form['#disable_inline_form_errors'] = TRUE;

Should we document this as an allowed key in https://www.drupal.org/node/2117411

I couldn't find anywhere in the code that we document allowed keys for top-level form and I don't think this fits on FormElement as it only applies to the top level form. Does anyone know if we have that somewhere?

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 65: 2856950-64.patch, failed testing. View results

dmsmidt’s picture

Status: Needs work » Needs review

I haven't seen a place where all top level form element properties are listed.

But we could at least add a paragraph about user feedback / error reporting of forms to the documentation page you mention. In there we can mention the new key.

berdir’s picture

StatusFileSize
new36.91 KB

Nothing there yet, but \Drupal\Core\Render\Element\Form might be a place to document that?

What about the login and password recovery form and similar forms that only have 1-2 form elements? Possibly disabling just the summary there might make more sense than disabling it completely (#2880011: Add a #disable_inline_form_errors_summary property to disable the Inline Form Errors summary but it is IMHO quite confusing that the message is on the username field when it could just as well be the password being wrong.

Also did a re-test, looked like random fails.

andrewmacpherson’s picture

I've no objection to disabling IFE on the user login page. The error message is a general one which applies to both fields, and has a call to action ("forgot?") which deserves prominence in the main messages area. It also serves as a good demonstration of the new FAPI property.

Should it be a blocker to this issue, or a follow-up?

skaught’s picture

forgot aside:
it's confusing that the link is on the username field when it's not even the password that has an error; in this situation. But, i know, this message is set for it's own purpose..

dmsmidt’s picture

Status: Needs review » Needs work

Setting this to needs work since we need documentation in code.

@Berdir (@andrew), please create a separate issue for individual forms that could use some improvement with IFE on. I don't agree to use to 'old' error messaging since we never know where the login form is in relation to the message. A shared message could also be put on a surrounding fieldset for example. @SKAUGHT it goes without saying that the messages should make sense.

dmsmidt’s picture

Status: Needs work » Needs review

So, I was thinking about the whole documentation thing mentioned by @larowlan #68 and @Berdir #71.
Adding documentation in code that not belongs to the IFE module seems strange, right?
We would then describe the usage of a key, which can only be used if the module is enabled. Doesn't sound legit. The same logic goes for the generic Form API documentation.

Currently the feature is mentioned on the IFE documentation page, this is IMHO the best spot for now.
https://www.drupal.org/docs/8/core/modules/inline-form-errors/inline-for...

dmsmidt’s picture

Status: Needs review » Reviewed & tested by the community

Putting this back to RTBC since no code was changed and tests still pass.
The only issue open for discussion was about documentation.
In code documentation about features added by a module should not be put in code that is not of that module.
There is documentation on DO (see #75), I'll update it when this gets in.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 65: 2856950-64.patch, failed testing. View results

dmsmidt’s picture

Status: Needs work » Reviewed & tested by the community
larowlan’s picture

Queued another test run

larowlan’s picture

Updating review credits

In code documentation about features added by a module should not be put in code that is not of that module.

As discussed on slack, I agree

  • larowlan committed 128cb26 on 8.5.x
    Issue #2856950 by dmsmidt, marcvangend, tim.plunkett, andrewmacpherson,...
larowlan’s picture

Status: Reviewed & tested by the community » Fixed

Committed as 128cb26 and pushed to 8.5.x.

As per https://www.drupal.org/core/release-cycle-overview#current-development-c... 8.4 is in 'critical fixes only', so this can't be backported to 8.4

larowlan’s picture

Published change record

dmsmidt’s picture

Hooray! I updated the IFE online docs to reflect the change.

Status: Fixed » Closed (fixed)

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