eca_form: "Form field: set as disabled" not working well for textarea widgets

Created on 30 April 2023, over 1 year ago
Updated 1 May 2023, over 1 year ago

Problem/Motivation

Flagging actions like "Form field: set as disabled" are currently having a complex problem with textarea widgets. Other types of widgets may be affected as well from this, as the mechanic is not bound to textarea widgets only. However it can be easily reproduced with that type of widget.

Basically with this problem, it's hard to disable textarea widgets using formatted text.

Steps to reproduce

Example:

Every new node type gets a body field. This field is a formatted text with summary field, and it's using a textarea widget for being displayed in a form.

Now try to create an ECA config that reacts upon "Process form" and then use "Form field: set as disabled" to disable the body value. A valid form field name would be "body.0.value". Same for the format body.0.format. Unfortunately this doesn't work for both. Interestingly though, it works for body.0.summary when the summary input is enabled.

Proposed resolution

There is no solution path yet for this problem, but the cause is known:

Textarea widgets are building up a render array using $element['#type'] = 'text_format'; as can be found in Drupal\text\Plugin\Field\FieldWidget\TextareaWidget. That render array will then be build up with its own process callback:
Drupal\filter\Element\TextFormat will add

return [
      '#process' => [
        [$class, 'processFormat'],
      ],
      '#base_type' => 'textarea',
      '#theme_wrappers' => ['text_format_wrapper'],
    ];

The form builder service will call all process callback from top to bottom. ECA will be fired up at the top, while the specified process callback of the textarea widget will be called later on as it is a child element of the form. There is currently no mechanic known where ECA could hook into afterwards. There is "After build form" event, but that one is way too late.

I was thinking about adding a process callback right into the element widget, but then I don't know what to do with it. Even worse, the validate callback of the flagging action won't find the targeted element, as it's not yet build up.

Remaining tasks

User interface changes

API changes

Data model changes

🐛 Bug report
Status

Fixed

Version

1.2

Component

Code

Created by

🇩🇪Germany mxh Offenburg

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @mxh
  • 🇩🇪Germany mxh Offenburg

    Ok, so it turns out that using "After build" is the proper event for such a case, because that's the only opportunity to change built up render arrays after all '#process' callbacks were executed by the form builder service.

    What's missing for the "Form field: set as disabled" action is, that the form builder does set HTML attributes right after the '#process' callbacks were executed, and after that it calls defined '#after_build' callbacks. That leads to the unfortunate situation, that the field is not being disabled by the proper HTML attributes when using "After build". At least for that, I could add a helper method to the according action plugin, that manually takes care for that. Providing an MR containing the helper method.

    There is one more problem though: The CKeditor element is always enabled, regardless when the form element was set to be disabled with $element['#disabled'] = TRUE;. This seems to be a core bug 🐛 ckeditor can't be set enabled / disabled / readonly by Form API #states Active
    We could consider providing a special treatment for CKEditor, or we forward this to a core issue, or at least treat this as a separate issue besides this one.
    Conclusion for CKeditor plugins: for the moment, there is no way at all to disable it. Luckily it's still possible to completely hide the field using "Form field: set access".

    Conclusion for the "After build" event: It may be more usable than originally thought. This may be appended in the ecaguide.org documentation, as others will probably also encounter this situation.

  • Open in Jenkins → Open on Drupal.org →
    Core: 10.0.7 + Environment: PHP 8.1 & MySQL 8
    last update over 1 year ago
    284 pass
  • @mxh opened merge request.
  • Status changed to Needs review over 1 year ago
  • 🇩🇪Germany mxh Offenburg
  • Status changed to RTBC over 1 year ago
  • 🇩🇪Germany jurgenhaas Gottmadingen

    This sounds like a deja vue as we ran into something related with CyPress tests where we wanted to assert, if the body field was empty. That failed, because the textarea html element is in the markup, but hidden. And the widget (CKEditor in this case) is a sibling div container to that textarea which does all the content editing input. Only when the form gets submitted is the value for the textarea being populated by javascript.

    Similar issues have been seen for the select2 drop-down widget, where javascript builds a widget next to the original form API element coming from Drupal.

    I'm commenting on this here because I assume that this behaviour is why disabling such fields that get special widgets won't be possible.

    The MR as such is looking good and will be committed.

  • Open in Jenkins → Open on Drupal.org →
    Core: 10.0.7 + Environment: PHP 8.1 & MySQL 8
    last update over 1 year ago
    284 pass
  • Status changed to Fixed over 1 year ago
  • 🇩🇪Germany jurgenhaas Gottmadingen

    Committed and back ported.

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

Production build 0.71.5 2024