Problem/Motivation

I noticed this issue while developing a relatively complex form, but I have since refined the problem down to a very simple form and have tested on a vanilla instance of Drupal 9.5.10.

The issue occurs when an element's state is built from a logical combination of multiple other fields.

For example:

  'visible' => [
    ':input[name="select1"]' => ['value' => 0],
    ':input[name="select2"]' => ['value' => 1],
  ],

Also note the same behaviour occur if written:

  'visible' => [
    ':input[name="select1"]' => ['value' => 0],
    'and',
    ':input[name="select2"]' => ['value' => 1],
  ],

Steps to reproduce

- BigPipe module has been installed.
- Use the following form:

  $form['select1'] = [
    '#type' => 'select',
    '#title' => 'Select 1',
    '#options' => [0 => 0, 1 => 1],
    '#default_value' => 0,
  ];

  $form['select2'] = [
    '#type' => 'select',
    '#title' => 'Select 2',
    '#options' => [0 => 0, 1 => 1],
    '#default_value' => 0,
  ];

  $form['select3'] = [
    '#type' => 'select',
    '#title' => 'Select 3',
    '#options' => [0 => 0, 1 => 1],
    '#states' => [
      'visible' => [
        ':input[name="select1"]' => ['value' => 0],
        'and',
        ':input[name="select2"]' => ['value' => 1],
      ],
    ],
  ];

After the form loads, you see the select elements 1 and 2. You don't see select 3 because the default values aren't as defined in #states.

If I select a value of 1 in select element 2, the values *should* be correct to trigger the appearance of select element 3. However, this doesn't happen.

Instead you have to set element 2 back to a value of 0, then again to a value of 1, before select element 3 appears.

Proposed resolution

Modules like big_pipe invoke attachBehaviors that results in multiple attachment of behaviors for a given context. If the attachBehavior is called multiple times, then in states multiple states.Dependent objects are created for the same elements. However the initialise is not called in Trigger function for all the states.Dependent object since it checks if it was already initialised for an element. Thus resulting in the bug. Proposed solution is to ensure that the states are attached only once.

- Approach 1: 3386191-states-not-working

Modify core/misc/states.js to use the library once to avoid duplicate attach calls multiple times.

Drupal.behaviors.states = {
    attach(context, settings) {
       // Uses once to avoid duplicates if attach is called multiple times.
      const elements = once('states', '[data-drupal-states]', context);

Issue fork drupal-3386191

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Ashley George created an issue. See original summary.

ashley george’s picture

shiv_yadav’s picture

Hi Ashley George,
Please use this type of coding after working for me visible functionality .
shared coding format:

$form['select1'] = [
'#type' => 'select',
'#title' => 'Select 1',
'#options' => [0 => 0, 1 => 1],
'#default_value' => 0,
];

$form['select2'] = [
'#type' => 'select',
'#title' => 'Select 2',
'#options' => [0 => 0, 1 => 1],
'#default_value' => 0,
];

$form['select3'] = [
'#type' => 'select',
'#title' => 'Select 3',
'#options' => [0 => 0, 1 => 1],
'#states' => [
'visible' => [
[':input[name="select1"]' => ['value' => 0]],
'and',
[':input[name="select2"]' => ['value' => 1]],
],
],
];

shiv_yadav’s picture

Status: Active » Needs review
smustgrave’s picture

Status: Needs review » Postponed (maintainer needs more info)

@Ashley George does that answer your question? If so this can be closed.

ashley george’s picture

@smustgrave unfortunately this doesn't seem to resolve things. After implementing the change suggested by @shiv_yadav the visibility on "select3" is now only linked to "select1". So I beleive there is still a valid issue here.

ashley george’s picture

Status: Postponed (maintainer needs more info) » Active
ashley george’s picture

Status: Active » Needs review
ashley george’s picture

Actually I'm not quite right with my description of how it's behaving now, but it's still not correct. If someone could see if they can replicate that would be awesome.

smustgrave’s picture

Status: Needs review » Active

I can confirm the issue you are seeing. I'm not entirely sure the cause.

At first I thought maybe states wasn't picking up the default value from select1 but that kinda is disproved by switching select2 to 0 and 1 again. Which triggered select3

Believe this is a valid bug, moving to Active for a patch/tests.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

sukr_s made their first commit to this issue’s fork.

sukr_s’s picture

Status: Active » Needs review

Modules like big_pipe invoke attachBehaviors that results in multiple attachment of behaviors for a given context. So maintain semaphore to ensure that the behavior is attached only once.

If the attachBehavior is called multiple times, then in states multiple states.Dependent objects are created for the same elements. However the initialise is not called in Trigger function for all the states.Dependent object since it checks if it was already initialised for an element. Therefore it's best to avoid multiple invocation of attachBehaviors to ensure that the behviors work as intended.

This fix ensures that attachBehavior is called only once for a given context

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests, +Needs issue summary update

Will need a test to show the bug.

Also issue summary appears incomplete, recommend using standard issue template

phthlaap changed the visibility of the branch 3386191-states-not-working to hidden.

phthlaap changed the visibility of the branch 3386191-states-not-working to active.

phthlaap changed the visibility of the branch 3386191-9x-states-not-working to hidden.

phthlaap’s picture

Issue summary: View changes
phthlaap’s picture

Status: Needs work » Needs review
phthlaap’s picture

Status: Needs review » Needs work
phthlaap’s picture

Issue summary: View changes
phthlaap’s picture

Issue summary: View changes
phthlaap’s picture

Status: Needs work » Needs review
sukr_s’s picture

StatusFileSize
new3.49 KB

@phthlaap the fix that you have provided is very specific to #states. The duplicates loading of attachBehavior can cause problems for any other module or custom module. So it's best to fix the root cause rather than in the affected module. Enclosed in a patch with tests for the same using #states for testing.

smustgrave’s picture

Status: Needs review » Needs work

If a different approach is being proposed can a separate MR be opened for reviewing. Issue summary will eventually have to be updated to match.

phthlaap’s picture

Issue summary: View changes
phthlaap’s picture

Status: Needs work » Needs review

The approach in patch #26 will affect some tests because I believe Ajax should reattach on form submission once again.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

phthlaap’s picture

Issue summary: View changes
Status: Needs work » Needs review
needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

phthlaap changed the visibility of the branch 3386191-states-not-working-drupaljs to hidden.

phthlaap’s picture

Status: Needs work » Needs review
needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

phthlaap’s picture

Issue summary: View changes
phthlaap’s picture

Issue summary: View changes
phthlaap’s picture

As suggestion of @nod_ , I use Once library to fix the issue. I think it is better.
I also changed the variable name $states because it is no longer a jQuery instance. but, it will be identical to the state variable defined at the top of the file, so I named it element.

phthlaap’s picture

Status: Needs work » Needs review
phthlaap’s picture

brunoalmeida’s picture

StatusFileSize
new3.42 KB

I have tested the last changes and I can confirm it's working.
I'm also adding a patch for the 10.1.6 core version.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

phthlaap’s picture

Status: Needs work » Needs review
Ozle’s picture

StatusFileSize
new476 bytes

I fixed this issue modifying only the $states variable to

const $states = once('states', '[data-drupal-states]', context);

smustgrave’s picture

@ozie can you try with tests though. Would have to be an MR

phthlaap’s picture

@smustgrave

The merge request above are already using same solution once library and also have a tests https://git.drupalcode.org/project/drupal/-/merge_requests/7045/diffs

smustgrave’s picture

MR also has additional changes besides that one line

phthlaap’s picture

As comment #40 I has explained, the variable name $states is no longer a jQuery instance. but, it will be identical to the state variable defined at the top of the file, so I named it element.

smustgrave’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests, -Needs issue summary update +Needs Review Queue Initiative

Removing the 2nd approach to avoid confusion

1) Drupal\FunctionalJavascriptTests\Core\Form\JavascriptStatesTest::testJavascriptStates
Failed asserting that false is true.
/builds/issue/drupal-3386191/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:121
/builds/issue/drupal-3386191/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:55
/builds/issue/drupal-3386191/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php:454
/builds/issue/drupal-3386191/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php:71
/builds/issue/drupal-3386191/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
FAILURES!
Tests: 1, Assertions: 203, Failures: 1.

Shows test coverage

Believe the change makes sense using once()

larowlan’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: +Needs issue summary update

Hi folks
Can we get an issue summary update that details why using once is the solution here.
Its not evident to me why that makes things different or why bigpipe is part of the issue.
Fine to self RTBC afterwards.

Thanks

sukr_s’s picture

IS updated as per #14 analysis

sukr_s’s picture

Issue summary: View changes
smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs issue summary update

IS is updated.

  • nod_ committed b02bce4a on 10.4.x
    Issue #3386191 by phthlaap, sukr_s, Ozle, brunoalmeida, smustgrave,...

  • nod_ committed e3b6f2fd on 11.0.x
    Issue #3386191 by phthlaap, sukr_s, Ozle, brunoalmeida, smustgrave,...

  • nod_ committed 5e2806f1 on 11.x
    Issue #3386191 by phthlaap, sukr_s, Ozle, brunoalmeida, smustgrave,...
nod_’s picture

Version: 11.x-dev » 10.4.x-dev
Status: Reviewed & tested by the community » Fixed

Committed and pushed 5e2806f1b5 to 11.x and e3b6f2fd67 to 11.0.x and b02bce4af0 to 10.4.x. Thanks!

eddylbs’s picture

Hello,
Patch from #46 works for me on 10.2.4
Thanks

  • nod_ committed 8905837f on 10.3.x
    Issue #3386191 by phthlaap, sukr_s, Ozle, brunoalmeida, smustgrave,...
nod_’s picture

Version: 10.4.x-dev » 10.3.x-dev

Status: Fixed » Closed (fixed)

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

cilefen’s picture

We have a report of a regression caused by this. I don't know whether this should actually be fixed in Webform. Perhaps the people on this issue can look into it.

gaurav_manerkar’s picture

We are facing issue because of this change. Conditional #states JS are not getting applied when element is refreshed/rendered by JS

nod_’s picture

a proper fix is in the works for core, could you test #3468860: JS #states behavior does not have a detach method. It should fix this but introduces another change in that #states about a missing element are now applied, they used to be ignored.