
Problem/Motivation
Currently it is not possible to target HTML classes to replace with AJAX, an ID must be used.
This sucks because the Form API goes to great lengths to make HTML IDs unique, which is why data-drupal-selector
was introduced back in 2015 when dinosaurs roamed the Earth (see https://www.drupal.org/node/2503277). Therefore, any element which you want to target with AJAX usually needs to be forcibly wrapped with markup to ensure an unchanging ID:
$element['#prefix'] = '<div id="ajax-target">';
$element['#suffix'] = '</div>';
Ugh. Besides being smelly code, the code which forcibly adds '#' to the wrapper string actually has a @todo to improve this situation. Let's do what it says, and make the AJAX targeting a little bit more flexible.
Proposed resolution
Leave #ajax['wrapper'] for BC, but introduce #ajax['selector'] instead.
Before:
'wrapper' => 'some-string',
After:
'wrapper_selector' => '#some-string',
Remaining tasks
N/A
User interface changes
N/A
API changes
#ajax['wrapper'] is deprecated, but has BC.
Data model changes
N/A
Comment | File | Size | Author |
---|---|---|---|
#76 | interdiff-74_76.txt | 1.08 KB | gauravvvv |
#76 | 2821793-76.patch | 42.49 KB | gauravvvv |
#75 | 2821793-75.patch | 42.49 KB | anchal_gupta |
#75 | interdiff-2821793-74_75.txt | 635 bytes | anchal_gupta |
#74 | 2821793-74.patch | 42.49 KB | gauravvvv |
Comments
Comment #2
tim.plunkettEverything in this is a straight conversion, except \Drupal\views_ui\ViewPreviewForm::actions() which is updated to use a class instead of an ID. All CSS is already targeting the class.
Comment #4
tim.plunkettelement_settings.selector is already used for other purposes.
Comment #6
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedComment #7
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedComment #9
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedComment #10
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedComment #12
tim.plunkettWhy are you removing necessary changes?
Comment #13
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedComment #14
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedComment #16
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedComment #17
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedComment #19
xjmRemoving issue credit for @Rajender Rajan since these patches are incorrect and do not advance the issue.
@Rajender Rajan, please post an explanation in the comment field and an interdiff when you update core patches, so that your contributions help move the Drupal core issues forward. You can also get help in IRC if you are not sure how to contribute. Thanks for your interest in working on Drupal core!
Comment #20
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedI am unable to understand error ! I thought i have done wrong changes that why its been showing error with each patch of mine !!!
Comment #21
tim.plunkettAll of your patches are invalid, so they will not apply.
But more importantly, why are you rolling patches that remove my changes?
Comment #22
Rajender Rajan CreditAttribution: Rajender Rajan as a volunteer and at gai Technologies Pvt Ltd for gai Technologies Pvt Ltd commentedMy patches invalid in what sense ? Can u please explain bit more ?
Comment #23
tim.plunkettThe patches you are uploading are invalid
I don't know how else to explain that part.
But more importantly, why are you deleting necessary parts of my changes?
Comment #24
tim.plunkettHere is a working patch with an interdiff against my last patch.
Comment #26
tim.plunkettClasses are not always alone, so must use contains.
Comment #28
tim.plunkettRerolled.
Comment #29
Sacrilegious CreditAttribution: Sacrilegious as a volunteer commentedDocs aren't fully updated. Property 'wrapper' is still listed as an option and 'wrapper_selector' isn't.
XPath query would fail in other case. E.g. if selector is 'textarea' or '[type="radio"]' or even ':empty'.
Can end up in invalid id because not only class (.) and id (#) selectors are valid 'wrapper_selector' values.
Comment #30
dinesh18 CreditAttribution: dinesh18 as a volunteer commentedIt should be if (isset($settings['wrapper_selector'])) and not if (isset($settings['wrapper'])) .
if (this.wrapper) should be replaced by if (this.wrapper_selector).
this.wrapper = null ----> this line should be removed
Comment #31
tim.plunkett@Dinesh18 no, both of those lines exist for backwards compatibility. They're fine as is
Comment #33
tim.plunkettComment #36
tim.plunkettRerolled, added a proper trigger_error for the deprecation, and fixed new occurrences.
Comment #38
tim.plunkettFixed the JS BC layer, and added @legacy to a test explicitly testing the old behavior.
Comment #40
tim.plunkettWhoops, that's
@group legacy
, not@legacy
Comment #41
tim.plunkettRerolled
Comment #42
panchoNice, however 'wrapper_selector' is a horrible name... :/
Seems like the collision anticipated in #4 didn't turn out to exist / be a problem, otherwise eschewing to 'wrapper_selector' would have fixed at least one of the #3 test failures.
Let's see if patch #41, with 'wrapper_selector' renamed back to 'selector', tests green as well. No other changes in here.
Comment #43
tim.plunkettIf that patch passes it only means there is missing test coverage for ajax.js.
Within the constructor for
Drupal.ajax
it provides a default value forselector
of`#${base}`
and defers toelementSettings
.That conflicts with the new
selector
you are adding here.Which I pointed out in #4 over 2 years ago.
Comment #45
tim.plunkettReuploading #41 again for the bot.
Comment #46
panchoYou were right, and the tests failed, too. Please ignore #42.
Let's however figure out if there's another way to have a concise property key.
Comment #47
panchoI weighed
#ajax['target']
as an alternative, but in the end, 'selector' is better, plus is used in AJAX commands, so should be used here, too. Let's see if we can fix that collision differently.Comment #48
tim.plunkettselector
is already used and it is not going away.Adjusting the docs.
Comment #49
panchoOK, unsubscribing.
Comment #50
lauriiiIt would be good to get sign off from a framework manager on this API change since changing 'wrapper' into 'wrapper_selector' is conceptually a big change. Using id as a selector ensures that the wrapper element is always unique. Since that is not the case after this change, I assume part of the scope is to allow returning content into multiple different wrapper elements from a single #ajax callback. We should document that in the issue summary explicitly since it is not a minor change. We should also add test coverage specifically for that.
Comment #51
lauriiiI tagged this for FM review because I accidentally thought there was no subsystem maintainer for ajax system. Moving this to the subsystem maintainer queue instead for addressing feedback in #50.
Comment #53
tim.plunkettI've been rerolling this patch for so long I forget why I started it in the first place.
The issue summary needs to explain *why* this should be fixed, and address the implications of what happens when using a non-unique selector.
Comment #54
phenaproximaImproved the problem/motivation section (I hope).
Comment #55
phenaproximaDiscussed this a bit with @tim.plunkett in Slack, trying to figure out what to do about the "multiple targeted elements" question. I felt that we should hard-code the system to only work on the first targeted element (
.eq(0)
), at least for now; Tim felt that we should allow multiple targets, and add test coverage. Since he is one of the maintainers of this subsystem, I think his opinion probably carries more weight than mine :) Tim also pointed out that nothing in core is currently taking advantage of multiple targeting, so things will continue to work the way they already do. In other words, although this change will expand the AJAX system's capabilities, it won't break existing code.So, okay. Multiple targeting it is. I'm tagging this issue for more tests and kicking it back for that.
Comment #56
berdirOne reason IMHO is that ids are, at least in certain places, dynamically altered, and if you're not extra careful, then ajax replacements no longer work the second time.
What I always wondered is why we added those data-drupal-selector attributes but afaik not use it anywhere (there might be an issue somewhere). You could also use the new selector to target these, probably just a bit unwieldy.
Comment #58
mglamanOne reason you would want to use this is if you are replacing the entire form on AJAX. You cannot keep replacing the form unless you ensure a stable ID.
Comment #60
tim.plunkettRerolled after #2619482: Convert all get_called_class()/get_class() to static::. No other changes yet.
Comment #62
tim.plunkettComment #63
anu.a_95 CreditAttribution: anu.a_95 commentedComment #64
anu.a_95 CreditAttribution: anu.a_95 commentedComment #65
anu.a_95 CreditAttribution: anu.a_95 commentedComment #67
tanubansal CreditAttribution: tanubansal at Salsa Digital commentedTested #62 on 9.1, Replace #ajax['wrapper'] with #ajax['wrapper_selector'] successfully applied
Comment #72
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 #73
solideogloria CreditAttribution: solideogloria commentedI think this issue is a good idea. If you want to embed a form in a block, and that block occurs more than one time on the same page, then you have an ID conflict due to hardcoding the wrapper ID. I don't know of any workaround as-is.
Comment #74
gauravvvv CreditAttribution: gauravvvv as a volunteer and at Axelerant for Drupal India Association commentedPatch #62, no longer applies to 10.1.x. I have re-rolled the patch #62, for 10.1.x. Please review
There is size difference with the patch #62, as es6.js files are removed from the current patch.
Comment #75
anchal_gupta CreditAttribution: anchal_gupta at Material for Drupal India Association commentedFixed CCF.
Comment #76
gauravvvv CreditAttribution: gauravvvv as a volunteer and at Axelerant for Drupal India Association commentedFixed CCF, attached interdiff with #74.
Comment #77
smustgrave CreditAttribution: smustgrave at Mobomo commentedDeprecation needs updating.
Also this was tagged for issue summary update 4 years ago. is #55 good enough?
Proposed solution could be cleaned up I think.
Comment #79
fathershawnWe are on a path to deprecate Ajax API. New functionality is now out of scope, however the new subsystem accepts any valid CSS selector by design. See #3404409: [Plan] Gradually replace Drupal's AJAX system with HTMX.
Comment #80
catchUsually for issues like this that we're hoping to make irrelevant, I move them to postponed on the issue/meta that will do that. That way there's a way to come back and point people to the new way when it's done, while still discouraging work on something that's unlikely to get reviewed/committed before it's removed anyway.
Marking postponed on #3404409: [Plan] Gradually replace Drupal's AJAX system with HTMX for now