Problem/Motivation
The issue happens when the module ui_patterns is enabled.
I use a custom component to embed a form :
$schema: https://git.drupalcode.org/project/sdc/-/raw/1.x/src/metadata.schema.json
name: Modal
description: Modal
group: Organisms
status: experimental
slots:
modal_body:
title: Modal body
props:
type: object
required:
- modal_id
properties:
modal_id:
type: string
title: Modal id
description: The id used in javascript to show/hide the modal. MUST be unique across the DOM
modal_header_title:
type: string
title: Text in the modal header
modal_content:
type: string
title: Text in the modal
additional_classes:
type: array
items:
type: string
title: Additional classes
This component is used as render array in a plugin block to include a form (Core user login form) in the modal_content property :
/**
* My custom login modal block.
*/
#[Block(
id: "my_module_header_mon_compte_block",
admin_label: new TranslatableMarkup("My module : Header MonCompte block"),
)]
class MonCompteModalBlock extends BlockBase implements ContainerFactoryPluginInterface {
...
/**
* Create the custom login modal block.
*
* @return array
* A render array.
*/
#[\Override]
public function build(): array {
return [
'#type' => 'component',
'#component' => 'my:modal',
'#props' => [
'modal_id' => $modal_id,
'modal_header_title' => $this->t('Mon espace'),
'modal_content' => [
'#theme' => 'modal_mon_espace',
'#user_login_form' => $this->formBuilder->getForm(UserLoginForm::class),
],
'additional_classes' => ['-user'],
],
],
}
...
Then this form is altered for ajaxified purpose :
/**
* Implements hook_form_alter().
*/
function my_module_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
...
$form['#prefix'] = '<div id="my_module_form_login_wrapper"><div id="my_module_form_login_wrapper_errors"></div>';
$form['#suffix'] = '</div>';
$form['actions']['submit']['#ajax'] = [
'wrapper' => 'my_module_form_login_wrapper',
// AJAX submit for checking any errors from core user login form validations.
'callback' => ['_my_module_ajax_submit_login_form'],
'event' => 'click',
];
$form['#attributes']['class'][] = '-modal-form';
...
}
Result => ajax does not seem to be applied. None related JS events bind to the submit handler.
Steps to reproduce
- Enable ui_patterns module
- Go to the page where block containing modal form component is displayed
- Ajax does not seem to be applied
- Disable ui_patterns module
- Go again to the page where block containing modal form component is displayed
- This time, ajax submit is working
Comments
Comment #2
a.depret commentedComment #3
a.depret commentedComment #4
smovs commentedComment #5
smovs commentedHi @a.depret!
I tested your issue locally, and the problem is that modal_content is declared in props rather than in slots. Props are meant for scalar values (strings, numbers, booleans), while slots are meant for renderable content like render arrays, and that distinction matters here.
When you put a render array into a string prop, ui_patterns has to coerce it into a string. That coercion happens in
UiPatternsNormalizer::convertArrayToScalar(), which calls:$value = (string) $this->renderer->renderInIsolation($array);The catch is that renderInIsolation() renders in a sandbox on purpose - it does not bubble #attached (JS libraries, drupalSettings, cache metadata) up to the page.
When modal_content is a slot instead, the value goes through
SlotPropType::normalize(), which keeps the render array intact. Drupal then renders it in the normal render context alongside the rest of the component, so #attached bubbles up the way it normally would, the AJAX library and settings reach the page, and the submit handler binds correctly.So the fix is just to move
modal_contentout ofpropsproperties and intoslots.Your block code doesn't need to change, 'modal_content' => [render array] is exactly what a slot expects. After drush cr, AJAX should work again.
Hope this helps! Let me know if you still have an issue with that.
Comment #6
smovs commentedComment #7
a.depret commentedHi @smovs !
Thanks a lot for your support.
With your full explanations, it worked like a charm !
My knowledge of the components is very limited, so sorry to having disturbed you.