From 3f1c18a171a5deebc3ff424db1a609ddca965b81 Mon Sep 17 00:00:00 2001
From: Lauri Eskola <lauri.eskola@acquia.com>
Date: Sat, 18 Feb 2023 16:40:01 +0200
Subject: [PATCH] Issue #2498791 by awset, ameymudras, balis_m, PQ, Kristen
 Pol, dww, morbiD, alexpott, smustgrave: #states defaultTrigger oldValue is
 out of date if values are updated via a state trigger

(cherry picked from commit 47f50b9dba7418fc510cf3f1e4c365a25e3fa600)
---
 core/misc/states.js                           |  2 +-
 .../src/Form/JavascriptStatesForm.php         | 46 +++++++++++++++++++
 .../Core/Form/JavascriptStatesTest.php        | 27 +++++++++++
 3 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/core/misc/states.js b/core/misc/states.js
index 487a41219083..39cd7b41bb3a 100644
--- a/core/misc/states.js
+++ b/core/misc/states.js
@@ -722,7 +722,7 @@
 
   $document.on('state:checked', (e) => {
     if (e.trigger) {
-      $(e.target).prop('checked', e.value);
+      $(e.target).prop('checked', e.value).trigger('change');
     }
   });
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php b/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php
index 4d589d349d35..4f8095739ff2 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php
@@ -31,6 +31,52 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#type' => 'textfield',
       '#title' => 'Textfield trigger',
     ];
+    $form['radios_opposite1'] = [
+      '#type' => 'radios',
+      '#title' => 'Radios opposite 1',
+      '#options' => [
+        0 => 'zero',
+        1 => 'one',
+      ],
+      '#default_value' => 0,
+      0 => [
+        '#states' => [
+          'checked' => [
+            ':input[name="radios_opposite2"]' => ['value' => 1],
+          ],
+        ],
+      ],
+      1 => [
+        '#states' => [
+          'checked' => [
+            ':input[name="radios_opposite2"]' => ['value' => 0],
+          ],
+        ],
+      ],
+    ];
+    $form['radios_opposite2'] = [
+      '#type' => 'radios',
+      '#title' => 'Radios opposite 2',
+      '#options' => [
+        0 => 'zero',
+        1 => 'one',
+      ],
+      '#default_value' => 1,
+      0 => [
+        '#states' => [
+          'checked' => [
+            ':input[name="radios_opposite1"]' => ['value' => 1],
+          ],
+        ],
+      ],
+      1 => [
+        '#states' => [
+          'checked' => [
+            ':input[name="radios_opposite1"]' => ['value' => 0],
+          ],
+        ],
+      ],
+    ];
     $form['radios_trigger'] = [
       '#type' => 'radios',
       '#title' => 'Radios trigger',
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php
index 259a7e146f06..80790d48f33b 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php
@@ -63,6 +63,7 @@ public function testJavascriptStates() {
     $this->doRadiosTriggerTests();
     $this->doSelectTriggerTests();
     $this->doMultipleTriggerTests();
+    $this->doNestedTriggerTests();
   }
 
   /**
@@ -322,4 +323,30 @@ protected function doMultipleTriggerTests() {
     $this->assertTrue($item_visible_value2_and_textfield->isVisible());
   }
 
+  /**
+   * Tests states of radios element triggered by other radios element.
+   */
+  protected function doNestedTriggerTests() {
+    $this->drupalGet('form-test/javascript-states-form');
+    $page = $this->getSession()->getPage();
+
+    // Find trigger and target elements.
+    $radios_opposite1 = $page->findField('radios_opposite1');
+    $this->assertNotEmpty($radios_opposite1);
+    $radios_opposite2 = $page->findField('radios_opposite2');
+    $this->assertNotEmpty($radios_opposite2);
+
+    // Verify initial state.
+    $this->assertEquals('0', $radios_opposite1->getValue());
+    $this->assertEquals('1', $radios_opposite2->getValue());
+
+    // Set $radios_opposite2 value to 0, $radios_opposite1 value should be 1.
+    $radios_opposite2->setValue('0');
+    $this->assertEquals('1', $radios_opposite1->getValue());
+
+    // Set $radios_opposite1 value to 1, $radios_opposite2 value should be 0.
+    $radios_opposite1->setValue('0');
+    $this->assertEquals('1', $radios_opposite2->getValue());
+  }
+
 }
-- 
GitLab