Problem/Motivation
When a form field is enabled/disabled via #states, the chosen update is fired before the element gets its disabled attribute updated.
Steps to reproduce
Create a simple form with a checkbox and a Chosen select whose enabled states depends on the checkbox.
$form['enabler'] = [
'#type' => 'checkbox',
'#title' => 'Enable',
];
$form['selecter'] = [
'#type' => 'select',
'#title' => 'Select',
'#chosen' => TRUE,
'#options' => [
'foo' => 'Foo',
],
'#empty_option' => '- Empty -',
'#states' => [
'enabled' => [
':input[name="enabler"]' => ['checked' => TRUE],
],
],
];
At the beginning the Chosen select is enabled while the actual select is disabled. When checking the checkbox, the Chosen select becomes disabled and the actual select becomes enabled.
Proposed resolution
jQuery always orders delegate event handlers before direct ones (both in 3.x and in 4.x). Drupal's states.js adds its states:disabled event handler as a direct one (both in 10.5.x and in 11.x). As this module's event handler is delegated as of 4.0.3, it will always trigger the chosen update first.
My proposed solution is to either put the chosen update into a setTimeout with a delay of 0, to execute it in the next event cycle,
$(document).on('state:disabled', 'select', function (e) {
setTimeout(function () {
$(e.target).trigger('chosen:updated');
});
});
or make the event handler a direct one and manually check the target.
$(document).on('state:disabled', function (e) {
if ($(e.target).is('select')) {
$(e.target).trigger('chosen:updated');
}
});
Although with the direct event handler, it must be ensured that this library is attached after the states library.
Remaining tasks
- Choose which solution to implement.
User interface changes
None.
API changes
None.
Data model changes
None.