FAPI #states do not update properly after AJAX requests.
Steps to reproduce
To replicate the bug, you need a content type with a field that makes an AJAX request and another field that has a state dependent on that field. In my use case, I have a content type with an image field and a text field that should only show when an image has been uploaded.
1. Have a content type with an image and a text field
2. Create a custom module that adds a state to your text field to only display when the image field has value. It would look something like this:
use Drupal\Core\Form\FormStateInterface;
function mymodule_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if ($form_id == 'node_page_form' || $form_id == 'node_page_edit_form') {
$form['field_my_text_field']['#states'] = [
'visible' => [
':input[name="files[field_my_image_field_0]"]' => ['filled' => TRUE],
],
];
}
}
3. Go to your content type and upload an image. You would expect to see field_my_text_field because the image field has an image and the state should react to the AJAX call. However, you won't see field_my_text_field. Save your node, and go back to edit your node. Now you should see field_my_text_field.
4. Apply the patch from #80 and go through the steps again. Now on step 3, you should see field_my_text_field immediately after you upload an image.
Original report
I use a custom module which makes heavy use of the Forms API to do mathematical calculations.
The form which you can see at http://linsenrechner.de/node/27 is rendered with the #states attribute. each line uses a container to display two fields. When these fields are filled, a new line should appear.
This works perfect, BEFORE the calculation button is pressed and the ajax request is done.
After this, the behaviour of the form changes: When two fields of a specific line are filled not only one new line appears. In this case, all lines, which are defined in the form, appear at the same time.
The author of the custom module, sukr_s (http://drupal.org/user/554988) wasn't able to exactly locate the bug, but believes it's in states.js
Here are the form arrays, which are used to create the form at http://linsenrechner.de/node/27
$form['container0'] = array(
'#type' => 'container',
'#weight' => -53,
);
$form['container0']['markup0'] = array(
'#weight' => -52,
'#markup' => "<div id='ocalc_header_33'></div>
<div id='ocalc_header_33'>$ocalc_sag_height</div>
<div id='ocalc_header_33'>$ocalc_zone</div>",
);
$form['container0'][$wrapper]['sag0'] = array(
'#type' => 'textfield',
'#title' => $ocalc_sag_height." 0",
'#title_display' => 'invisible',
'#weight' => -51,
'#maxlength' => 4,
'#size' => 4,
'#prefix' => "<div class='form-item-sag0'>$ocalc_zone 0</div>",
'#field_suffix' => "mm",
);
$form['container0'][$wrapper]['zone0'] = array(
'#type' => 'textfield',
'#title' => $ocalc_zone." 0",
'#title_display' => 'invisible',
'#weight' => -50,
'#maxlength' => 4,
'#size' => 4,
'#field_suffix' => "mm",
);
$form['container1'] = array(
'#type' => 'container',
'#weight' => -43,
'#states' => array('visible' => array(
':input[name=sag0]' => array ('filled' => TRUE),
':input[name=zone0]' => array ('filled' => TRUE),
),
),
);
$form['container1'][$wrapper]['sag1'] = array(
'#type' => 'textfield',
'#title' => $ocalc_sag_height." 1",
'#title_display' => 'invisible',
'#weight' => -42,
'#maxlength' => 4,
'#size' => 4,
'#field_suffix' => "mm",
'#prefix' => "<div class='form-item-sag1'>$ocalc_zone 1</div>",
);
$form['container1'][$wrapper]['zone1'] = array(
'#type' => 'textfield',
'#title' => $ocalc_zone." 1",
'#title_display' => 'invisible',
'#weight' => -41,
'#maxlength' => 4,
'#size' => 4,
'#field_suffix' => "mm",
);
$form['container2'] = array(
'#type' => 'container',
'#weight' => -33,
'#states' => array('visible' => array(
':input[name=sag0]' => array ('filled' => TRUE),
':input[name=zone0]' => array ('filled' => TRUE),
':input[name=sag1]' => array ('filled' => TRUE),
':input[name=zone1]' => array ('filled' => TRUE),
),
),
);
$form['container2'][$wrapper]['sag2'] = array(
'#type' => 'textfield',
'#title' => $ocalc_sag_height." 2",
'#title_display' => 'invisible',
'#weight' => -32,
'#maxlength' => 4,
'#size' => 4,
'#field_suffix' => "mm",
'#prefix' => "<div class='form-item-sag1'>$ocalc_zone 2</div>",
);
$form['container2'][$wrapper]['zone2'] = array(
'#type' => 'textfield',
'#title' => $ocalc_zone." 2",
'#title_display' => 'invisible',
'#weight' => -31,
'#maxlength' => 4,
'#size' => 4,
'#field_suffix' => "mm",
);
$form['container3'] = array(
'#type' => 'container',
'#weight' => -23,
'#states' => array('visible' => array(
':input[name=sag0]' => array ('filled' => TRUE),
':input[name=zone0]' => array ('filled' => TRUE),
':input[name=sag1]' => array ('filled' => TRUE),
':input[name=zone1]' => array ('filled' => TRUE),
':input[name=sag2]' => array ('filled' => TRUE),
':input[name=zone2]' => array ('filled' => TRUE),
),
),
);
$form['container3'][$wrapper]['sag3'] = array(
'#type' => 'textfield',
'#title' => $ocalc_sag_height." 3",
'#title_display' => 'invisible',
'#weight' => -22,
'#maxlength' => 4,
'#size' => 4,
'#field_suffix' => "mm",
'#prefix' => "<div class='form-item-sag1'>$ocalc_zone 3</div>",
);
$form['container3'][$wrapper]['zone3'] = array(
'#type' => 'textfield',
'#title' => $ocalc_zone." 3",
'#title_display' => 'invisible',
'#weight' => -21,
'#maxlength' => 4,
'#size' => 4,
'#field_suffix' => "mm",
);
$form['container4'] = array(
'#type' => 'container',
'#weight' => -13,
'#states' => array('visible' => array(
':input[name=sag0]' => array ('filled' => TRUE),
':input[name=zone0]' => array ('filled' => TRUE),
':input[name=sag1]' => array ('filled' => TRUE),
':input[name=zone1]' => array ('filled' => TRUE),
':input[name=sag2]' => array ('filled' => TRUE),
':input[name=zone2]' => array ('filled' => TRUE),
':input[name=sag3]' => array ('filled' => TRUE),
':input[name=zone3]' => array ('filled' => TRUE),
),
),
);
$form['container4'][$wrapper]['sag4'] = array(
'#type' => 'textfield',
'#title' => $ocalc_sag_height." 4",
'#title_display' => 'invisible',
'#weight' => -12,
'#maxlength' => 4,
'#size' => 4,
'#field_suffix' => "mm",
'#prefix' => "<div class='form-item-sag1'>$ocalc_zone 4</div>",
);
$form['container4'][$wrapper]['zone4'] = array(
'#type' => 'textfield',
'#title' => $ocalc_zone." 4",
'#title_display' => 'invisible',
'#weight' => -11,
'#maxlength' => 4,
'#size' => 4,
'#field_suffix' => "mm",
);
Comment | File | Size | Author |
---|---|---|---|
#186 | 1091852-186.patch | 10.67 KB | david.muffley |
#177 | 1091852-177.patch | 10.65 KB | Nicolas S. |
#173 | 1091852-nr-bot.txt | 145 bytes | needs-review-queue-bot |
#172 | interdiff-171_172.txt | 697 bytes | Gauravvvv |
#172 | 1091852-172.patch | 13.31 KB | Gauravvvv |
Issue fork drupal-1091852
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
Comment #1
sukr_s CreditAttribution: sukr_s commentedPlease review the patch to fix the above problem and needs to be integrated in to the main batch.
Comment #3
sukr_s CreditAttribution: sukr_s commentedtrying again with the patch instruction from http://drupal.org/node/3060/git-instructions/7.x
Comment #5
sukr_s CreditAttribution: sukr_s commentedCan someone help on how to create a patch with git.
i followed the instruction from http://drupal.org/node/3060/git-instructions/7.x and named the patch as
[description]-[issue-number]-[comment-number].patch (comment 3). it does not work
and in comment 2 used
http://drupal.org/node/1054616 and named the patch [issue-number]-[description]-[comment-number]-D.patch
and this too did not work.
which of the two instructions are correct or did i miss something completely?
Comment #6
sukr_s CreditAttribution: sukr_s commentedOne more attempt...
Comment #7
danSamara CreditAttribution: danSamara commentedSame problem.
Thanks, patch work for me.
Comment #8
Anonymous (not verified) CreditAttribution: Anonymous commentedNice work on getting the patch up. This didn't work for my issue, but I probably have a different issue in my module.
I'm marking it as needs work because there are some whitespace errors. I noticed this when I applied the patch because the command line returned this message: "3 lines add whitespace errors." If you use Dreditor, you'll be able to see the errors in pink.
Comment #9
sukr_s CreditAttribution: sukr_s commentedremoved spaces
Comment #10
Anonymous (not verified) CreditAttribution: Anonymous commentedLooks good except for one thing.
There is still a space at the end of this comment.
Powered by Dreditor.
Comment #11
sukr_s CreditAttribution: sukr_s commentedwondering how that escaped...
Comment #12
andypostPlease make a patch against current 8-dev and use no D7 suffix to allow testbot run tests
EDIT Anybody can review this from performance side?
Comment #13
sukr_s CreditAttribution: sukr_s commenteduploading 8.x ported patch
Comment #15
sukr_s CreditAttribution: sukr_s commentedi pulled
and created the patch, but it has failed. I tried with 8-dev & 8.x-dev, but got a warning that both 8-dev and 8.x-dev does not exist. pls advise on the branch to use for creating patch.
Comment #16
andypostTestbot cant get your patch because of '(' in filename
so please reroll with a simple name like
1091852-multiple-states.patch
Comment #17
sukr_s CreditAttribution: sukr_s commented@andypost: Thanks for your tip.
rerolling patch with clean name.
Comment #18
andypostLinked this issue with original issue to get 2 review #557272: FAPI: JavaScript States system
Also a lot of thanx to @dannie-walker module that demonstrates this bug
Comment #19
rfaySubscribe. Some time ago I created a general #states testing regimen at https://github.com/rfay/states_exercise . Last I looked at it a few things didn't look like they worked right at all, but I didn't pursue it.
Comment #20
wjaspers CreditAttribution: wjaspers commentedsub.
Comment #21
BerdirI have a similar issue, but I'm actually replacing a number of elements which have #states attached.
Basically, there is a select and for each value, there is a checkboxes element which shows up for a option of that select. Based on yet another radios element, I'm replacing all checkboxes elements with another set of them (different values/labels). The reason for that is that a combined #states definition does not seem to work reliably, after clicking around it falls apart and shows both options or something like that.
Without this patch, all checkboxes elements show up initially but after changing the select, it works correctly. With this patch, this stops working completely.
The inline comments in the patch also need work, they shouldn't be longer than 80 characters, be real sentences with a dot at the end, start with an uppercase character and a space before.. e.g. "// This is a correct inline comment."
Comment #22
akamaus CreditAttribution: akamaus commentedAs Bendir I ran into the problems with the patch attached to #11. Without it after the first ajax call my js handler attached to document to 'state:required' event starts being called about a dozen of times on each value change of controlling select box. With this patch applied to D7.14 the state system seems to be totally disabled, no reactions on select box changes seem to occur.
Comment #23
akamaus CreditAttribution: akamaus commentedI made some further experiments. Looks like the patch #11 works on D7.14 if corrected a bit.
here I had to replace 'dependees' with 'constraints'.
Comment #24
hibersh CreditAttribution: hibersh commentedpatch against drupal 7.x
Comment #25
Atomox CreditAttribution: Atomox commentedAny plans to roll this into a D7 release?
This also works for our issues.
Comment #26
Dmitriy.trt CreditAttribution: Dmitriy.trt commentedLast patch fails in our case. States event handler don't get re-binded to the AJAX-loaded elements, so it's impossible for other elements to depend on their state.
Comment #27
amar.deokar CreditAttribution: amar.deokar commentedLast patch also not worked for me. I am doing same as mentioned in comment #26.
Comment #28
alexweber CreditAttribution: alexweber commentedWeirdest thing, #24 worked in Chrome but not in Firefox, no errors to speak of though...
Comment #29
vyvee CreditAttribution: vyvee commentedWeird for me... #24 doesn't work for me at all, even in Chrome.
Comment #30
gagarine CreditAttribution: gagarine commentedI tested the patch #24 on Chrome 35 and Firefox 30. It works and I don't see how it could fail. Perhaps it was a browser cache problem?
Comment #31
gagarine CreditAttribution: gagarine commentedI see, if you replace the element with AJAX the states are not applied to this element again.
I think was what committed in D8 don't works neither but this should be tested.
Not sure how to fix that.. Any idea?
Comment #32
jgullstr CreditAttribution: jgullstr as a volunteer commentedThe states are not initialized on AJAX-requests, as the initialization is blocked by states.Trigger by the code
The reason to this guard is stated in the code to be
I'll have to examine further why this is necessary and how to solve the problem.
I'm not sure adding a states.CreateState function that checks for duplicates is the optimal solution. Wouldn't adding a behavior.detach method, that removes all traces of removed states, be a cleaner solution?
Comment #33
jgullstr CreditAttribution: jgullstr as a volunteer commentedHere's a patch that tries to solve the lack of initial states application after AJAX requests. In order to make it work without messing up the API (ie custom state callback function implementation), I have repurposed the dependee elements "triggered" data attribute. Instead of containing a flag whether or not the trigger has been initialized, it now contains the current value of that state for that trigger, and loads initial value from that when behaviors are attached.
This patch does not attempt to solve the issue with cleaning up orphaned dependants.
Comment #34
jgullstr CreditAttribution: jgullstr as a volunteer commentedOops, looks like a went a little trigger happy on the upload button.
Comment #35
rooby CreditAttribution: rooby commentedThanks for the patch, this is a very frustrating bug for me at the moment.
I have a had a quick try and it seems to work in most cases but I've found a case where it is still a problem.
I have an addressfield where one of the fields in it is shown/hidden with states based on a set of radios outside the addressfield.
Whenever I select a country and the addressfield ajax runs, my states controlled field appears, regardless of which radio button is selected.
It is possible that this may be some other unrelated issue so I will investigate further.
Comment #36
rooby CreditAttribution: rooby commentedStrange. I've done nothing since my last test but now it is working even for the addressfield case.
I will report back if it stops working again.
Comment #37
rooby CreditAttribution: rooby commentedNot sure if it's just me but I'm having problems when I have ajax that loads new fields that weren't originally on the form or removes fields from the form that have states.
Initially I was getting these errors:
for line 319 of states.js:
Just to see what would happen (since I don't yet have much knowledge of how it all works) I changed it to:
and it fixed the error, after which states are working for fields that were always on the form but not for ones that were added via ajax.
(this is unrelated to my previous addressfield ramblings.)
Comment #38
rooby CreditAttribution: rooby commentedRelated issue #2226405: FAPI #states: dependent element added via AJAX initializes incorrectly if dependee has been initialized earlier
Comment #39
rooby CreditAttribution: rooby commentedIt turned out I had some other bugs that were causing states to not work on new form elements added by my ajax, however the "TypeError: this.element.data(...) is null" bug remains.
I now have this working successfully with my form, which is a pretty good use case of a large drupal commerce checkout form that has a complex set of visibility and required field states, a lot of form alters, custom ajax and custom javascript.
I will roll an updated patch with my fix for the is null bug.
Comment #40
rooby CreditAttribution: rooby commentedUpdated patch.
I assume this is also going to need new tests.
[edit] Damn, I forgot to re-check the comment number before I posted.
Comment #41
fbrier CreditAttribution: fbrier commentedI am having a problem with a Javascript multi-page FAPI form when wrapped in ctools so as to bring up a modal dialog. The page advance just hides fieldset(s) using the #states triggered by a hidden field. It works before bringing up the modal dialog, but after bringing up and dismissing the modal dialog, the HTML field the selector specifies changes, but the #states do not hide/show their fieldsets(s). trigger() is explicitly being called on the tag using the selector, plus it works before the modal is opened/closed.
Initially my problem sounded like this bug #1592688: #states can cause the form "required" mark to appear more than once on the same element. Feeling in luck since the new 7.40 release was rolled out yesterday, I upgraded. Unfortunately, it did not fix it. So I cloned the git repo, branched 7.40, applied the above drupal-states_after_ajax-1091852-39.patch, and copied states.js up to the server. No change in behavior. Now David_Rothstein patch was also to the states.js file, but obviously to 7.39. Would this make a difference? The patch appeared to apply cleanly. Thank you.
Comment #42
hestenetComment #43
moonray CreditAttribution: moonray at Chapter Three commentedA similar (or the same) problem seems to be happening with D8 as well. I'll test the patch (and adapt it where need it) on D8 and report back.
Comment #44
moonray CreditAttribution: moonray at Chapter Three commentedThis is definitely an issue in D8.
The D7 fix (manually applied) doesn't work for me in D8 and would need to be tweaked/fixed.
Comment #45
moonray CreditAttribution: moonray at Chapter Three commented(removed duplicate post)
Comment #46
Anonymous (not verified) CreditAttribution: Anonymous commentedThe patch in #40 is working for me.
Comment #47
Anonymous (not verified) CreditAttribution: Anonymous commentedComment #48
stefan.r CreditAttribution: stefan.r commentedIdeally this should be fixed in D8 first (where I believe we can also now add tests for this).
Comment #49
sumthief CreditAttribution: sumthief as a volunteer and at DrupalJedi commentedConfirm that patch from #40 works perfect for 7.50 on my current project.
Comment #50
stefan.r CreditAttribution: stefan.r commentedThis also applies to Drupal 8 per #44, so assigning this to 8.x per the backport policy.
Possibly we already have an existing issue for this?
Comment #51
stefan.r CreditAttribution: stefan.r commentedComment #52
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedComment #53
nbouhid CreditAttribution: nbouhid as a volunteer and at CI&T commentedI created a module that provides a temporary fix for those that does not want to patch the core and wait until this fix gets merged: https://www.drupal.org/sandbox/nbouhid/2776183 (D7)
We're using it and it works fine.
Comment #54
odegard CreditAttribution: odegard commentedThanks nbouhid! Working as advertised. I've got a doublefield showing both fields if different field A is X and only one field if A is Y. The old states.js showed both fields even when A is Y after adding another item. The new states.js fixes this.
Comment #56
ron_s CreditAttribution: ron_s commentedFor anyone using patch #40 or the sandbox project created by @nbouhid for Drupal 7, there are two critical errors. CKEditor fails to load every time in a ctools popup window (such as for Panels) due to these lines of code:
The error generated by the console is as follows, pointed at
$dependee.data()
and!this.element.data()
, respectively:It does not matter if using the CKEditor or WYSIWYG modules, it fails in both cases. Rolling back the patch fixes the problem.
Comment #57
ron_s CreditAttribution: ron_s commentedAttached is an updated patch for review that checks if the objects are defined. Thanks.
Comment #58
Tim Bozeman CreditAttribution: Tim Bozeman at CyberSolution for CyberSolution commented#57 is a good addition!
I was getting the AJAX + states display bug and #40 fixed it, but I was getting
Uncaught TypeError: Cannot read property 'hasOwnProperty' of undefined
which was fixed by #57.Comment #60
kalistos CreditAttribution: kalistos at Adyax commentedThanks #57 helped me, but it's on Drupal 8.2, so I have updated it for Drupal 8.3.
Comment #61
ron_s CreditAttribution: ron_s commented@kalistos, patch #57 is not Drupal 8.2. It is for Drupal 7.
Comment #62
droplet CreditAttribution: droplet commentedComment #63
idebr CreditAttribution: idebr at ezCompany commentedClosed #2864632: Form states not working when form loaded via ajax? as a duplicate
Comment #65
jwilson3Patch in #60 doesn't apply to 8.4.x since the move to es6 for all javascript.
Comment #66
Ivan Berezhnov CreditAttribution: Ivan Berezhnov as a volunteer and at Drupal Ukraine Community for Levi9 commentedComment #67
kfritscheFirst a re-roll. Not setting to needs review as I'm currently also doing some small changes, but for this an interdiff would be good.
Comment #68
kfritscheWhy change from on to bind?
Unnecessary change in my mind.
Don't like this, to much clutter :/
This is also not needed in my mind. As we just can check for undefined. jquery data does the rest.
Changes applied.
Comment #70
kfritscheSmall issue on the second change from #68. For second occurrence it needs to be checked for equals undefined.
Also adding patch for 8.4.x if anybody else needs it (we do)
Comment #72
mohit_aghera CreditAttribution: mohit_aghera as a volunteer and at Axelerant commentedTested this with 8.4.x and seems working fine.
Tested with nested paragraph and related #states logic, works fine with paragraphs as well.
Comment #73
alexpottWe need a JavascriptTestBase test for this. We can now test javascript interaction in D8 so a failing test without the fix and a passing test with the fix would great.
Comment #74
nwoodland CreditAttribution: nwoodland commentedPatch from #70 works great on 8.5. Thanks!!
Comment #75
idebr CreditAttribution: idebr at ezCompany commentedThe patch in #70 needs a reroll after #2917234: [2/2] JS codestyle: no-restricted-syntax was committed.
Comment #77
idebr CreditAttribution: idebr at ezCompany commentedReroll after the following issues were committed:
- #2981652: [Aug. 9 2018] Format core JavaScript using recently add Prettier
- #2917234: [2/2] JS codestyle: no-restricted-syntax
Still needs a tests to show the current failing behavior.
Comment #78
nikathoneJust to mention that the patch #40 fixed my issue on a d7.60.
Comment #79
AndySipple CreditAttribution: AndySipple commentedUpdated core from 8.5 to 8.6.3. Patch #70 applied cleanly on 8.5 but does not apply cleanly on 8.6.3.
Comment #80
TwoDRe-rolled again because the compiled version no longer applied.
Comment #82
tstoecklerHEAD was broken...
Comment #83
Nuuou CreditAttribution: Nuuou commentedPosting this here as it's relevant to an issue I ran into recently.
These patches work great. However, it also seems to conflict in an odd way with the Webform module. Nothing that's terribly bad, but definitely noticeable. Related issue thread:
https://www.drupal.org/project/webform/issues/2996530
Again, not sure if this is actionable, but might be of interest if anyone else notices this!
Comment #84
idebr CreditAttribution: idebr at iO commentedThe issue reported in #83 in the Webform module has been resolved, see #2996530: AJAX Settings visibility state based on non-existing DOM element
The webform module evaluated the visibility of a container on the value of a non-existing DOM element. Currently, this is evaluated as 'visible' but after applying the updated States logic implemented here this evaluates as 'invisible'. It was solved by removing the
visibility
states implementation.Comment #85
mukun CreditAttribution: mukun commentedUpdated core from 8.3.9 to 8.6.7. Patch #60 works on 8.3.9 but does not applied on 8.6.7.
message was could not apply patch while update core.
Comment #86
Nuuou CreditAttribution: Nuuou commented@mukun: I'm currently applying patch #80 with Drupal 8.6.7, and it's applying cleanly. Might wanna try that out!
Comment #88
nwoodland CreditAttribution: nwoodland commentedPatch from #80 on Drupal 8.6.13 and PHP 7.2.15 works great. Thanks!
Comment #89
carletexI had the same issue (#states not working after an AJAX call) and patch #80 fixed the issue.
Tested on Drupal 8.6.13.
Comment #90
jonathanshawIn order to make a test, it would help to have clear steps to reproduce.
Comment #91
angelamnr CreditAttribution: angelamnr commented@jonathanshaw: To replicate the bug, you need a content type with a field that makes an AJAX request and another field that has a state dependent on that field. In my use case, I have a content type with an image field and a text field that should only show when an image has been uploaded.
1. Have a content type with an image and a text field
2. Create a custom module that adds a state to your text field to only display when the image field has value. It would look something like this:
3. Go to your content type and upload an image. You would expect to see field_my_text_field because the image field has an image and the state should react to the AJAX call. However, you won't see field_my_text_field. Save your node, and go back to edit your node. Now you should see field_my_text_field.
4. Apply the patch from #80 and go through the steps again. Now on step 3, you should see field_my_text_field immediately after you upload an image.
Comment #92
geaseI have added a test based on module from #18 to #2702233-80: [backport] Add JavaScript tests for Form API #states: required, visible, invisible, expanded, checked, unchecked
Comment #93
geaseComment #94
geaseThe patches add a test to the patch from #80. As Form State API tests are being developed in #2702233: [backport] Add JavaScript tests for Form API #states: required, visible, invisible, expanded, checked, unchecked, I extended the patch from #2702233-76: [backport] Add JavaScript tests for Form API #states: required, visible, invisible, expanded, checked, unchecked with a test based on module from #18.
Uploaded patches contain:
1091852_with_2702233-full.patch - patches from current issue #80, #2702233-76: [backport] Add JavaScript tests for Form API #states: required, visible, invisible, expanded, checked, unchecked, and the test for current issue. It should pass tests.
2702233-80.patch - tests from #2702233-76: [backport] Add JavaScript tests for Form API #states: required, visible, invisible, expanded, checked, unchecked extended with the test for the current issue, but without the patch for the current issue. This should fail through testing.
1091852-93.patch - patch from #80 and test for it, applied over #2702233-76: [backport] Add JavaScript tests for Form API #states: required, visible, invisible, expanded, checked, unchecked. This should even fail applying to 8.8.x until the latter patch is committed.
Comment #96
jonathanshawIt would help to get a JS maintainer to look at this now.
Comment #98
adam-delaney CreditAttribution: adam-delaney commentedI've tested https://www.drupal.org/files/issues/2019-09-12/1091852_with_2702233-full... and it applies cleanly and resolves my issue.
https://www.drupal.org/files/issues/2019-09-12/1091852-93.patch against 8.7.10 does not apply.
Thanks for the work on this issue.
Comment #99
adam-delaney CreditAttribution: adam-delaney commentedUPDATE https://www.drupal.org/files/issues/2019-09-12/1091852_with_2702233-full..., introduces a regression where the revision log field is hidden when new nodes are created. Is this intended behavior?
Comment #100
rensingh99 CreditAttribution: rensingh99 at Red Crackle commentedHi,
I have applied the patch #93 with 8.9x and it failed to apply.
I have made it compatible with 8.9x.
And there was some error as per Drupal coding standard I have solved that too and uploaded the patch with interdiff.
After that, I have tested the patch and it worked as design.
Below are my updates.
1). I have added the text field in the article content type.
2). I have made it dependent on the image field using hook_form_alter().
Before applying the patch
The text field didn't show after uploading the image. Below is the output screenshot.
After applying the patch
The text field did show after uploading the image. Below is the output screenshot.
The patch is working great.
Thanks,
Ren
Comment #102
rensingh99 CreditAttribution: rensingh99 at Red Crackle commentedComment #103
rensingh99 CreditAttribution: rensingh99 at Red Crackle commentedComment #104
Dave ReidWe've identified that this actually causes a regression with the "Revision log message" field on new nodes. Because it has a state that is dependent on the revision checkbox being checked, and on new forms this checkbox is not in the form at all, the revision log field is hidden when it should not be. I've included a change that fixes this to add the state conditionally in ContentEntityForm. But this will need test coverage to ensure it does not break. As such I'm marking this as Needs work for now.
Comment #105
mdolnik CreditAttribution: mdolnik as a volunteer and commentedPatch #104 is working for us in 8.8.x
Comment #106
bgreco CreditAttribution: bgreco commentedPatch #104 solves a slightly different issue for me on 8.8.x.
I have an entity form that includes a Media Library widget. It includes a second field whose #states depend on the value of a third field. If I load the form and click "Add media", the #states on the second field no longer work, despite the Media field not being involved in the #states at all. I think the patch fixes my issue because of its care to not to call the state changes multiple times.
Comment #107
nodecode CreditAttribution: nodecode commentedI'm coming from #3114741: [#States API] AJAX and Conditionals Conflicting and can confirm that patch #104 resolves this and multiple related issues with the Webform module, states, and AJAX. I'm currently on Drupal 8.8.2.
Comment #108
Andras_Szilagyi CreditAttribution: Andras_Szilagyi at Randstad Digital for European Commission and European Union Institutions, Agencies and Bodies commentedTested #104, works great, I also added the 7.2 and 7.3 env tests, green.
Patch has great tests and interdiff, what are we waiting for ?
Comment #109
jonathanshawPer #104 this needs a little more test coverage, so cannot be RTBC
Comment #111
joshua.boltz CreditAttribution: joshua.boltz at Mediacurrent commentedI'm seeing similar issues to this when using #states for conditional field logic on node forms, although instead of the ajax coming from a custom form like in this issue, the ajax would be from paragraphs with its edit links.
On typical node add and node edit forms, it's working great.
But, in my site, I have a case where via paragraphs, there is an entity reference field using entity browser, that allows users to edit the referenced entities within the entity browser, and when clicking the Edit link the first time, the #states work. But if i close that window and try to Edit another reference node in there, the #states does not work.
Here is my #states code
I also tried this patch and it did not solve the issue.
See screenshot - https://www.drupal.org/files/issues/2020-07-01/Screen%20Shot%202020-07-0...
Comment #112
joshua.boltz CreditAttribution: joshua.boltz at Mediacurrent commentedComment #113
joshua.boltz CreditAttribution: joshua.boltz at Mediacurrent commentedComment #115
seanBReroll for 9.1.x
Comment #116
akasake CreditAttribution: akasake commentedReroll for 9.0.x based on #115
Comment #117
Darren OhComment #118
jannakha CreditAttribution: jannakha as a volunteer and at Tomato Elephant Studio commented102 worked for 8.9! Hurray!
Comment #119
jannakha CreditAttribution: jannakha as a volunteer and at Tomato Elephant Studio commentedComment #120
beckydev CreditAttribution: beckydev commented#104 resolved our issue on 8.9.13.
Comment #121
dalinHere's a reroll, both for 9.1, and HEAD of 9.2.
Someone definitely needs to check these tests. I know a little about PHP tests, and nothing about JS tests. I hope I didn't mangle them.
Comment #122
dalinThe drop is always moving. Here's another reroll to catch up to HEAD, and to fix the linting issues.
But again, someone who understands JS tests needs to review the tests.
Comment #123
raman.b CreditAttribution: raman.b at OpenSense Labs commentedComment #124
LendudeWhen you reroll, please check that the patch size stays roughly the same. We lost about half the patch (all the new test coverage) between #115 and #116. So please reroll but base this on a version that still contains everything please.
Comment #125
idebr CreditAttribution: idebr at iO commentedComment #126
dalinI think the confusion in the tests is because much of it was committed in at least three other issues:
https://git.drupalcode.org/project/drupal/-/blame/9.2.x/core/tests/Drupa...
https://git.drupalcode.org/project/drupal/-/blame/9.2.x/core/modules/sys...
But we did seem to loose
\Drupal\FunctionalJavascriptTests\Core\Form->testAjaxJavascriptStates()
core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php
core/modules/system/tests/modules/ajax_forms_test
We'll need to get those back before this is commitable.
Comment #127
carletexFollowing @Lendude and @dalin comments, this is my attemp to reroll the patch from #115 (so we don't loose what @dalin mentioned) to catch up with 9.2.x.
Comment #128
idebr CreditAttribution: idebr at iO commentedThe JSWebAssert changes were removed on purpose in #2702233: [backport] Add JavaScript tests for Form API #states: required, visible, invisible, expanded, checked, unchecked, see comments #105 -> #109
Attached updated the assertions in
\Drupal\FunctionalJavascriptTests\Core\Form\JavascriptStatesTest::testAjaxJavascriptStates()
method to match the other assertions in the file.Comment #131
roderikThis patch solves a related but different issue for me: if fields are dynamically added to the form by an AJAX call, which have #states (depending on a form item that was present already)... those #states are not applied.
Before I started messing with the JS, I added tests for that situation.
Disclaimer: I cannot properly review this because I'm not a JS developer; I only get half of the code.
But I noticed that
...removes the only code that changes states.postponed. So if this is the right way of doing things, we should remove any reference to states.postponed.
Tried that; the tests still succeed.
My biggest question now is: are we even allowed to essentially replace this whole
states.postponed.push()
mechanism with the single call tothis.reevaluate()
in states.Dependent?I'm thinking it wasn't there for nothing. It feels like
reevaluate()
from being called on the dependent objects too many times,reevaluate()
when 'things' may not be fully initialized yet.I'm guessing it's the second. I'm guessing this 'postponed' mechanism had a good reason for being there. But this JS makes my head spin so I can't answer that.
(I tried reverting the removal of the above code + addition of the
this.reevaluate()
call, but that made things fail again.)Comment #132
roderikPHPCS + Yarn + CSpell...
Comment #134
roderikSo summarizing, AFAICT this needs
Comment #135
jonathanshawIt sounds like #104 could be triggered by a form alter anyway, even without this issue. In which case, yes it's a good candidate for handling as a separate issue. I'm happy to do reviews on that issue if you'll code it.
Comment #136
jonathanshawGiven this is an old, major bug that's proven difficult to fix, I think it's reasonable to ask for a js maintainer's review. Which may answer #131.
Comment #141
owenbush CreditAttribution: owenbush at Lullabot commentedI've cleaned up patch #132 (there was a .rej file presumably from a previously failed patch which I have removed) and put it into a merge request so that any changes can be more easily added.
I attempted to add the tests mentioned in #104 and #134 and am wondering whether it would be better to break those out elsewhere. Ideally we need a test entity with revisions enabled in order to test the revision log message field does not disappear after an AJAX request. Core does have the entity_test_revlog entity with revision logging enabled, but there are no forms and routes configured that are accessible to the javascript functional tests. So should testing that functionality live with the entity_test tests, or still within the Javascript state tests. I'm happy to try again with the tests, but not sure as to the desired approach. Thoughts welcome.
Comment #142
jonathanshawI think so
Sounds like we'll need to add them.
Seems like this is really an issue with the revision logging, not generically with the javascript states. So entity_test... I'd say.
Comment #143
roderikYes, it feels like testing that part is best off connected to 'whatever else Core has in that area' (entities, revisions, I'm not aware of the setup of those tests personally). And doesn't need to be tied in with the JS + its tests at all.
Comment #144
yoshiet p CreditAttribution: yoshiet p commentedPatch #104 seems to be working fine in my use case where #states would not initialize after ajax request.
Comment #145
mibfire CreditAttribution: mibfire commentedhttps://www.drupal.org/project/drupal/issues/1091852#comment-11611711
I have an issue with Views Bulk Operations (VBO) module when there is only one option that you can modify in bulk, for example when you want to modify values of a reference field of nodes.
In this case this one option will be hidden
, because the "show value" checkbox is changed to "#type = 'value'"
https://git.drupalcode.org/project/views_bulk_operations/-/blob/7.x-3.x/...
and when "this.reevaluate();" runs in "states.Dependent = function (args) {" then it hides it because i think the dependency is not in the html.
misc/states.js:48
I have a proposal for the fix, but i am not sure this is the right one and covers all cases. I think we should check if at least one selector exists in the html and if yes we call the "this.reevaluate()" function only in this case.
As i see this affects Drupal 8 & 9 too.
Comment #146
mibfire CreditAttribution: mibfire commentedComment #147
mibfire CreditAttribution: mibfire commentedI made a patch based on https://www.drupal.org/files/issues/drupal-states_after_ajax-1091852-57.... for VBO issue(https://www.drupal.org/project/drupal/issues/1091852#comment-14225149).
Comment #148
jonathanshawWas there a reason you didn't use the latest version as discussed in #141?
Additionally, it helps enormously if you can provide an interdiff.
Comment #149
mibfire CreditAttribution: mibfire commented@jonathanshaw
Why would i have used that patch? when i fixed the d7 version not the Drupal 8&9 version. I made the diff though.
Comment #150
tbsiqueiraI'm re-rolling the patch to be able to apply to a 9.1.x core version, I also removed a couple of duplicated files and tests, for now I just need to apply the code change.
Comment #152
VladimirAusWork fine.
Comment #153
catchJavaScript linting is failing.
Comment #154
superlolo95 CreditAttribution: superlolo95 commented+1 for #150
Comment #155
yogeshmpawarFixed CS issues.
Comment #156
bryantgeorge CreditAttribution: bryantgeorge commented#155 seems to fix the issue for me
Comment #157
jonathanshawNW for #142 test tidy up.
Comment #159
akalam CreditAttribution: akalam at Dropsolid commented#155 is working for me
Comment #160
szato CreditAttribution: szato at Brainsum for Novozymes A/S commented#155 and MR749.diff works for me, but there is an another (maybe separate?) issue:
I'm using paragraphs on modal and using same machine name for fields with states on parent node and in paragraphs too. Because of the same field machine name, states on modal doesn't work only on the parent node form. If I use separate field machine names, the states works in parent node form and in paragraphs modal form too.
Comment #162
sker101 CreditAttribution: sker101 as a volunteer commentedI'm having a similar issue with an ajax callback applied element on one of our webforms and confirmed that the patch #155 fixes my issue.
However, I'm seeing some regressions on the form after applying the patch due to using multi wizard page on the form.
We have a select element on wizard page 2 and its visible condition is depending on another element which only exists on the wizard page 1.
After applying the patch, the select element on wizard page 2 is no longer visible regardless what value we have on the element of wizard page 1.
Our solution for now is to create a form alter to make the element on wizard page 1 visually hidden on wizard page 2 so that the value could be
respected by the select element on wizard page 2.
Due to this issue, we have to thoroughly review all other webforms we have on the site that use multi wizard page.
Comment #163
michaelsoetaertI've re-rolled the patch in #155 on the 9.5x branch.
Comment #164
_utsavsharma CreditAttribution: _utsavsharma at OpenSense Labs for DrupalFit commentedComment #165
adam-delaney CreditAttribution: adam-delaney commentedI'm not able to apply patch #163 with Drupal 9.5 with error, `patch fails to apply`.
Comment #166
adam-delaney CreditAttribution: adam-delaney commentedComment #167
adam-delaney CreditAttribution: adam-delaney commentedSorry, I've made a mistake checking our build output. Putting back into needs review
Comment #168
_utsavsharma CreditAttribution: _utsavsharma at OpenSense Labs for DrupalFit commentedFixed CCF for #163 for 9.5.x.
Please review.
Comment #170
edmund.dunn CreditAttribution: edmund.dunn at Agile Six Applications for Department of Veterans Affairs commentedRerolled patch for 9.5 because it wouldn't apply.
Comment #171
seanBAnother attempt to reroll #155.
Comment #172
Gauravvvv CreditAttribution: Gauravvvv at Axelerant for Drupal India Association commentedFixed CCF, attached interdiff for same. Please review
Comment #173
needs-review-queue-bot CreditAttribution: needs-review-queue-bot as a volunteer commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #174
DrColossos CreditAttribution: DrColossos at CYLEDGE commented#172 applies and works in 9.5.3
Comment #175
yovanny.gomez.oyola CreditAttribution: yovanny.gomez.oyola at Globant commented#172 applies and works in 9.5.5. Thanks!
Comment #176
Nicolas S. CreditAttribution: Nicolas S. commentedPatch #172 works for me with a Drupal 9.5.9
Comment #177
Nicolas S. CreditAttribution: Nicolas S. commentedFix patch for Drupal 10.1.x
Comment #180
SajithAthukorala CreditAttribution: SajithAthukorala as a volunteer commentedHaving Issues with #132 on Drupal Version 9.5.9 132: 1091852-132.patch , It gives an errors on page load where we use #states attributes in fields. This may cause the page load js errors and not recommend to use it . Thank You !!!
Comment #181
adam-delaney CreditAttribution: adam-delaney commentedI've tested Drupal 10.1 with a clean install using the steps in the description to reproduce the issue and I'm not able to reproduce it. This seems to have been fixed in states.js for Drupal 10.
Comment #182
maithili11 CreditAttribution: maithili11 as a volunteer and at Axelerant commentedPatch #172 works for me with a Drupal 9.5.8
Comment #183
Dave ReidI can no longer replicate this issue on Drupal 9.5 or 10 and I think the fix in #1988968: Drupal.ajax does not guarantee that "add new JS file to page" commands have finished before calling said JS core issue, but I haven't been able to confirm that. I think we need someone to provide a reproducible scenario (I used the one in the issue description, and I could no longer reproduce it) or possibly close this as fixed. I do wish I knew exactly what core issue seems to have resolved it, I don't feel easy closing this until we know.
Comment #184
david.muffley CreditAttribution: david.muffley commentedI'm still having this issue on a form submit button whose state depends on some facets elements. #177 resolves the issue for me. I'll try to produce a trimmed down reproducible scenario like the one I'm experiencing soon™.
Comment #185
Robin.Houtevelts CreditAttribution: Robin.Houtevelts at Wieni commentedI can also confirm I'm still having this problem on 10.1.
Applying #177 resolved it for me.
Comment #186
david.muffley CreditAttribution: david.muffley commentedRerolled #177 for 10.2.
Comment #187
keshavv CreditAttribution: keshavv as a volunteer and at Axelerant for Drupal India Association commentedConfirm I'm still having this problem on 10.2.
Applying #186 resolved it for me.
Comment #188
jonathanshaw@robin.houtevelts @keshavv steps to reproduce - or at least come comments on the circumstances in which you're encountering this bug - would be really helpful.
Comment #189
chrisgross CreditAttribution: chrisgross commentedI'm still having what I think is the same issue and the latest patch does not fix it. Perhaps this is a slightly complicated example, but I will simplify it as best as possible.
Here I have I two select lists. The first one uses an ajax callback to modify the options contained within the second one, which has a couple hardcoded default values:
My custom
equipmentUpdate
callback does a lot of other things, but here is the command I use to update the options of the second select list:This
ReplaceCommand
occurs after$equipment
(which is a copy of$form['equipment']['equipment_id']
) has been modified to add new values after the two defaults set earlier.That functionality works just fine, but what does not is the state of a third field, whose visibility depends on a value contained within the second select list, which is modified by the ajax call:
Before the ajax callback, the visibility of this text field is correctly controlled by the
equipment_id
select list. After the callback completes, this no longer works, and the visibility of this field does not change. I have tested by experimenting with other ways of organizing the data and using different ajax commands, likeHtmlCommand
, but nothing works. No matter what I do, subsequent ajax calls continue to correctly modify the select list values, but the visibility state of the text field is broken.I have confirmed that all the markup in all fields and wrappers are exactly the same before and after the ajax command, except that that ajax operations change element ids, for example, from
edit-equipment-id
toedit-equipment-id--Ronn-Os05Q0
. But my visibility selector is targeting thename
attribute, which does not change, so this shouldn't matter.I have been able to work around this by not using
ReplaceCommand
to replace the entire select element and instead manipulate the option elements directly:This works, but should not be necessary, as replacing the entire select list should not cause the states of another field to stop working. Doing it this way is also mildly inconvenient because, as far as I can tell, I cannot pass options as a render array (or a subset thereof) to the ajax commands, so I have to write the markup for each option manually.
It seems that simply replacing a form element that is the dependency of another element, even with an identical copy of itself, breaks states for the dependent element, whereas modifying the contents does not.