Problem/Motivation
Bug in Drupal 7.x.
For example, page contains at least two different forms. If submit one of them and validation fails I will recieve this forms with same element IDs.
If I use AJAX I may got an unexpected behavior, because jQuery thinks that I have no duplicates in DOM. It takes first element with needed ID and process it using AJAX.
But needed ajax element might be second in the DOM, and AJAX was processed wrong element.
To test this you should enable ajax register and contact modules. Put login block into the second sidebar, then logout and go to /contact page. When you get there, just submit contact form. No data should be filled (you should get a validation error).
Then open any web developer tool (I tested in firebug) and search for #edit-name or #edit-submit element. You'll find it in contact form and in the loggin form. Then try to submit contact form again and you will see that this button was processed with AJAX.
Proposed resolution
Problem
Proposed resolution
Also I've got a solution: When element was not validated in drupal_process_form function drupal_static_reset('drupal_html_id');
shouldn't be called, because it breaks correct ID's count.
Patch that solves that problem is attached.
Remaining tasks
User interface changes
API changes
Comment | File | Size | Author |
---|---|---|---|
#65 | 1414510-core-htmlid-54.patch | 3.17 KB | David_Rothstein |
#62 | form_validate.patch | 2.04 KB | perelman.yuval |
#61 | form_validate.patch | 2.04 KB | perelman.yuval |
#59 | form_validate.patch | 2.11 KB | perelman.yuval |
#58 | before.jpg | 43.59 KB | andypost |
Comments
Comment #1
aspilicious CreditAttribution: aspilicious commentedThe next test also tests on form_get_errors() so I believe this is a correct fix.
Comment #2
aspilicious CreditAttribution: aspilicious commentedSrry needs work again, we need to fix this first in D8. Can you provide a d8 patch too?
Comment #3
SpleshkaSure, patch attached.
Should I write any tests or this fix is obvious?
Comment #4
SpleshkaSorry for version and status change. It was happened by accident.
Comment #5
andypostI think better to add unit test to form.test to ensure that
drupal_html_id
static is not cleared when form has validation errorsComment #6
aspilicious CreditAttribution: aspilicious commentedYeah like andypost says you should write a test :)
Comment #7
SpleshkaTest is attached.
Comment #8
andypostI recommend attach this test to AJAXMultiFormTestCase::testMultiForm
right now HEAD is broken so patch testing postponed 'til #61456-91: Aggregator titles display quotes and other characters with HTML entity equivalents badly (write tests)
Comment #10
SpleshkaPatch with fix and test.
Comment #11
andypostLet's get this one commited, and please re-roll same path for D7
But I still prefer to see this test as part of
testMultiForm
as I pointed in #8Comment #12
SpleshkaPatch for D7.
Comment #14
andypostPosting patch for D7 you should change Version accordingly
#10 still ready to be commited
EDIT @Spleshka - let's get #10 commited and then roll a patch for D7, also you could use -d7.patch suffix for D7 patched within D8 issues (they're not be tested)
Comment #15
catchThis and other comments don't meet Drupal's coding standards - they should be a full sentence with a full stop. See http://drupal.org/coding-standards for more. There's also some whitespace issues in the patch - extra line breaks etc.
Also please upload the test as a patch by itself so the test bot can show it fails OK.
Comment #16
andypost@catch #7 has only test that shows breakage
#10 is actual patch for D8 should be re-rolled without extra line breaks in testFormValidationFails()
@Spleshka #12 whitespace issue in D7 patch
Comment #17
SpleshkaThanks for your notes. Here is patch for D8.
Comment #18
SpleshkaPatch for D8 without extra line breaks in testFormValidationFails().
Comment #19
SpleshkaSame patch for D7.
Comment #20
andypost#18 is good to go but ...
I think this comment should be changed to say about why static is not cleared when form has errors.
Comment #21
andypost@aspilicious please post your opinion about test and check English grammar
Comment #22
aspilicious CreditAttribution: aspilicious commentedThe comment is not ok. You maybe can write:
"Tests that element ID's don't get duplicated when form validation fails."
if it is shorter than 80 chars. I'm not sure if it has to be IDs or ID's.
These comments are not needed, code is clear enough.
Can you upload a patch with only tests and a patch with the test and the fix (only D8)
Comment #23
andypostTest itself been posted at #7 results http://qa.drupal.org/pifr/test/218633
Comment #24
andypostThere's already test for 2 node forms, just extended it a bit
1414510-ajax-test.patch - just a test
1414510-ajax-with-test.patch - patch with test
locally both fails, but if I manually enable
drush en form_test -y
and make submit second node form with empty title - IDs are differentSo let's see what bot will say
Comment #26
Spleshka@andy, your patch didn't pass the test, so I attached my own.
Comment #27
andypost@Spleshka sheck my test and comment, your test is edge case but with ajax it somehow broken
Comment #28
sunThe patch in #24 looks better to me. However, we should revise the existing comment in form.inc and do a better job of clarifying why this condition/exception exists. (I don't fully understand it yet.)
That said, it's also a bit strange that the simple test in #26 failed, too.
Comment #29
andypost@sun test fails without patch because after validation of contact form form elements gets the same IDs
login form also gets same IDs - edit-name, edit-actions and edit-submit
Comment #30
sunah, thanks, that explains it. yeah, #26 relies on way too much coincidence then. ;)
Comment #31
tim.plunkettSo the patch with test in #24 still fails 4 times, because instead of there being page-node-form and page-node-form--2, there are two page-node-form--2.
Probably not a surprise, just my results from running the test locally.
Comment #32
andypost@tim.plunkett can you explain i different behaviour of local & bot's fails in #24 - why locally
Comment #33
tim.plunketthttps://skitch.com/plnktt/8pkx9/ajax-test-with-two-form-instances-drupal
Both node form's get page-node-form--2 after validation fails.
Comment #34
andypostI know about this but can't understand why #24 breaks this
Probably #node-form needs special processing or some hook_forms hacks
Comment #35
tim.plunkettI don't think it breaks it, all of the fails in #24 with-fix are also in #24 test-only: http://qa.drupal.org/pifr/test/220473 http://qa.drupal.org/pifr/test/220478.
Comment #36
andypostProbably today we found another cause of this trouble. In case of form with file element
jquery.form.js wrongly serializes
extraData
and ajax_html_ids are passed as string to drupal backendComment #37
andypostNew patch that should fix problem, core passes ajax_html_ids as array but in case of multipart data serialization fails.
EDIT I'm using space character as separator becaouse
HTML5 allows any chars
to be used as ID. Probably html5 innitiative should take care about this.Patch still needs better comment as @sun suggests in #28
Exception is thrown when jquery.form.js gets updated to latest version (uses strict JS) #1574560: Update jQuery Form Plugin to the latest in the git repository
Also this should help to move #956186: Allow AJAX to use GET requests
Comment #39
andypostAnother round to fix tests
Comment #41
andypostI found a way to reproduce failure - just add any field to content type with unlimited cardinality.
Patch just moves field creation after a testing IDs.
So it means that field API breaks html_ids but this is out of scope this patch
Comment #42
andypostJust a test
Comment #44
andypostFinally here's a new test.
Patch with just the test to make sure that functionality broken
Comment #45
andypostFiled separate issue about ajax_html_ids #1575060: ajax_html_ids are broken for forms with file element (encoding=multipart/form-data)
Comment #46
andypostSimplified test, cleaned comments
Comment #47
andypostAnother fix of comments
Comment #48
tim.plunkettRerolled for form.test PSR-0
Comment #49
star-szrTagging.
Comment #50
geekyMoa CreditAttribution: geekyMoa commentedPatch in #48 passed manual test.
Tested by..
Comment #51
tim.plunkettExcellent! Thanks.
Comment #52
tim.plunkettIt needed a minor reroll for the static class property $modules instead of setUp, leaving RTBC.
Comment #53
catchThanks! Committed/pushed to 8.x. Moving to 7.x for backport.
Comment #54
andypostPatch for D7
EDIT Also
ajax_html_ids
totally broken and needs to be fixed for forms with file field #1575060: ajax_html_ids are broken for forms with file element (encoding=multipart/form-data)Comment #55
arvinsingla CreditAttribution: arvinsingla commentedCame across a situation where this issue occurred. Tested the D7 port patch and works brilliantly.
Comment #56
webchickI think this makes sense (and comes with lovely tests, even!) but I'd love to get David's eyeballs on this before committing, since it does represent a change in behaviour.
Comment #57
David_Rothstein CreditAttribution: David_Rothstein commentedSorry for the delay.
I've been staring at this for a while and have yet to figure out exactly why the patch is safe. As far as I can tell, it relies on the fact that a form with errors will be rebuilt and re-displayed later on, or something like that. I can't figure it out from the code comment either, so I'm going to have to put this aside and look again later. This is touching some pretty fundamental stuff and I don't want to commit it to Drupal 7 until I really understand how it works, sorry.
As an aside, this patch does not fix the both-forms-get-the-validation-error bug shown in the screenshot in #29 (nor is it actually trying to). I was pretty confused by that, because when you test this with the contact form you see the same behavior either way... But it seems like that's just a separate bug entirely.
Comment #58
andypost@David_Rothstein bug with high-ligting errors totally out of scope this issue.
Also this change is not so fundamental and I think better to include it into upcoming release.
You can test it manualy by:
1. Patch only tests hunk
2. enable form_test module
3. visit
4. see the html-id
5. try to submit any form
See the attached screenshots
Comment #59
perelman.yuval CreditAttribution: perelman.yuval commentedHi all, i make a patch to fix the both-forms-get-the-validation-error, i know this is not the issue here but i cant find the relevant one, so i upload it here.
I dont sure if it is the right solution, so plase review and give me feedback.
Comment #61
perelman.yuval CreditAttribution: perelman.yuval commentedupload the patch again this time from linux.
Comment #62
perelman.yuval CreditAttribution: perelman.yuval commentedComment #63
andypostStill waiting #54 to be commited, #59-62 is irrelevant
@perelman.yuval your changes are out of scope this issue - please file new one in D8 queue and drop a link here
Comment #65
David_Rothstein CreditAttribution: David_Rothstein commentedI think I convinced myself that this patch is safe, but incomplete. So, we can commit it to Drupal 7 and file a followup issue for the rest.
I'll get it committed soon. Reuploading #54 now for the testbot.
Comment #66
David_Rothstein CreditAttribution: David_Rothstein commentedI filed a followup issue with a possible patch at #1831560: Remove Html::resetSeenIds() call during form processing.
As I mentioned above, the screenshot shown in #29 looks like an independent bug also, so it would be great if someone filed a followup issue for that one too (if it doesn't exist already).
Thanks!
Comment #67
andypost@David_Rothstein I glad to see this commited and have follow-up for errors highlighting - probably @perelman.yuval work could be used as starting point. As I figured out this issue about to fix html_id generation for forms in case of validation error.
The error highlight is caused by using element name and not ID - so it's different task and probably is not applicable for D7 backport
Comment #68
David_Rothstein CreditAttribution: David_Rothstein commentedCommitted to 7.x - thanks! http://drupalcode.org/project/drupal.git/commit/577bfdc
Just to clarify, by the way (since I think #66 and #67 were crossposts), there are two possible followups here:
Comment #69
David_Rothstein CreditAttribution: David_Rothstein commentedComment #71
fagoRelated issue: #2034631: Remove drupal_reset_static for drupal_html_id() during form processing
Comment #71.0
fagoAdded bare issue summary template