#states not working correctly when built from a logical combination of multliple fields

Created on 8 September 2023, 9 months ago
Updated 29 May 2024, 4 days ago

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);
๐Ÿ› Bug report
Status

Needs review

Version

11.0 ๐Ÿ”ฅ

Component
Formย  โ†’

Last updated about 5 hours ago

Created by

๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom Ashley George

Live updates comments and jobs are added and updated live.
  • Needs issue summary update

    Issue summaries save everyone time if they are kept up-to-date. See Update issue summary task instructions.

Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Issue created by @Ashley George
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom Ashley George
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia shiv_yadav

    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]],
    ],
    ],
    ];

  • Status changed to Needs review 8 months ago
  • Status changed to Postponed: needs info 8 months ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

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

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom Ashley George

    @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.

  • Status changed to Active 8 months ago
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom Ashley George
  • Status changed to Needs review 8 months ago
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom Ashley George
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom Ashley George

    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.

  • Status changed to Active 8 months ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    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.

  • First commit to issue fork.
  • Pipeline finished with Failed
    3 months ago
    Total: 184s
    #119636
  • Status changed to Needs review 3 months ago
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia sukr_s

    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

  • Status changed to Needs work 3 months ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    Will need a test to show the bug.

    Also issue summary appears incomplete, recommend using standard issue template

  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap

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

  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap

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

  • Merge request !7077Added tests and fix code for Drupal 9.x โ†’ (Open) created by phthlaap
  • Pipeline finished with Failed
    3 months ago
    Total: 164s
    #122583
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap

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

  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • Status changed to Needs review 3 months ago
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • Pipeline finished with Failed
    3 months ago
    Total: 522s
    #122609
  • Status changed to Needs work 3 months ago
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • Pipeline finished with Canceled
    3 months ago
    Total: 146s
    #122634
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • Pipeline finished with Success
    3 months ago
    Total: 523s
    #122636
  • Status changed to Needs review 3 months ago
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia sukr_s

    @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.

  • Status changed to Needs work 2 months ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    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.

  • Pipeline finished with Failed
    2 months ago
    Total: 175s
    #123807
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • Pipeline finished with Failed
    2 months ago
    Total: 649s
    #123813
  • Status changed to Needs review 2 months ago
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap

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

  • Status changed to Needs work 2 months ago
  • 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.

  • Status changed to Needs review 2 months ago
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • Status changed to Needs work 2 months ago
  • 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.

  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap

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

  • Status changed to Needs review 2 months ago
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • Status changed to Needs work 2 months ago
  • 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.

  • Pipeline finished with Success
    2 months ago
    Total: 648s
    #134554
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • Pipeline finished with Success
    2 months ago
    Total: 606s
    #134606
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap

    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.

  • Status changed to Needs review 2 months ago
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap
  • 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.

  • Status changed to Needs work about 2 months ago
  • 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.

  • Status changed to Needs review about 2 months ago
  • ๐Ÿ‡จ๐Ÿ‡ดColombia Ozle Bogotรก

    I fixed this issue modifying only the $states variable to

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

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

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

  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap

    @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

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    MR also has additional changes besides that one line

  • ๐Ÿ‡ป๐Ÿ‡ณVietnam phthlaap

    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.

  • Status changed to RTBC 5 days ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    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()

  • Status changed to Needs review 4 days ago
  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia larowlan ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ.au GMT+10

    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

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia sukr_s

    @Iarowllan the analysis was provided in #14. Copying the same below for convenience.

    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.

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia sukr_s
Production build 0.69.0 2024