- Issue created by @psebborn
Did you test by removing the changes in π The attachBehaviors() for document is only called after Big Pipe chunks are processed Fixed to verify that it in fact is the issue that changed this behavior?
- π¬π§United Kingdom psebborn
Yes, I removed the changes from this commit https://git.drupalcode.org/project/drupal/-/commit/0c57711#80205155285d2... and the problem goes away.
I've updated the description to include this information, too.
- πΊπ¦Ukraine abramm Lutsk
In fact, this is an expected behavior.
Drupal behaviors may (and will) be called multiple times if something on a page changes, e.g. with either AJAX or Big Pipe.Using once() is not a workaround; it's a requirement for any behavior in Drupal either initializing any objects specific to DOM element, adding event listener or any similar thing that should only be ran once.
It's being shipped with Drupal for the exact same purpose.You may also notice once() allows passing in context as one of the arguments.
- Status changed to Closed: works as designed
almost 2 years ago 1:32pm 1 February 2023 - π²π©Moldova nyph1337
I encountered this same issue on my project which previously had already had a lot of javascript implemented without using once(). This issue is genuinely the cause of turning off BigPipe, in fact at this point it is cheaper for our team to implement another custom mini-variation of BigPipe instead of reworking our behaviors to use once().
#4 This is absolutely an issue and your module should be designed to have it. While I agree that once() method gives you more guarantees and add more safety - it should be just a fail-safe for those rare cases when duplicate attachBehaviors() cannot be avoided. This should not mean that we all just start neglecting the context param and throw attachBehaviors() at will, uncontrollably. The context param should only contain the newly-added HTML that came through AJAX, and I am sure that BigPipe can and should be accountable of that, its just a bit more technically challenging.
The official drupal.org Javascript API overview docs β never says its a "requirement" but rather a "guarantee" and the article is right to suggest it because a lot of modules, like BigPipe, do it wrong.
- πΊπΈUnited States gpotter
I agree with #7, we have to make a conversion to make this work as well. It was a very easy to understand the concept before of attaching listeners to the context parameter (new html will flow through context once), but now being require to use once() adds additional complexity and boilerplate code.
- πΊπ¦Ukraine abramm Lutsk
The once() requirement is not something new; it's always being there and you could hit the same issue, for example, if you'd run AJAX on a page.
The concept of JS behaviors implies that behaviors could be ran multiple times on the same page, there's nothing new with it.This may be easily confirmed be checking JavaScript API overview documentation page β .
- πΊπΈUnited States gpotter
Sorry Abramm you are correct, just really running into these issues now at Drupal 9.5 after never having issues for years. I think many older tutorials make it vague and like its an either/or type of situation where attaching context to listeners is a magic bullet that is really not the case anymore (EX: https://www.lullabot.com/articles/understanding-javascript-behaviors-in-...)
This is ridiculous. I already have trouble convincing front-end developers to use the context parameter in our custom modules (most of them just ignore it since don't understand its logic). Now I have to convince them to use jQuery once. When the rest of the javascript world is moving away from jQuery we are forcing people to use it. It doesn't make any sense. I will disable this module on any site I have to work on.
- π¦πΊAustralia larowlan π¦πΊπ.au GMT+10
Fwiw once is a standalone library, not jQuery
https://www.drupal.org/project/drupal/issues/3347144 π Form API #states property/states should use .once() to apply its rules (Can cause failures with BigPipe and possibly other situations) Needs work in this bug it fails to properly handle Drupal States when you have a fairly complex multi level states layout, so there is a bug here, I'm not sure if #3347144 is the correct fix or just fixing the symptom
- πΊπ¦Ukraine abramm Lutsk
#3347144 is definitely a bug in States. It would fail with AJAX scenario as well, not only with Big Pipe.
- π¦πΊAustralia silverham
Echoing sentiment :-(
All of our JavaScript/jQuery will have to be updated too.
From:
[my_theme.libraries.yml]global-js: version: 1.0 js: assets/js/main.js: {} dependencies: - core/jquery
[main.js]
(function ($, Drupal, once) { Drupal.behaviors.myThemeOrModule = { // Both single or multiple elements is fine. $('.selector', context).addClass('my-class'); // Multiple elements. $('.views-row', context).each(function(i, element) { $(element).addClass('my-class'); }); }; })(jQuery, Drupal, once);
To:
[my_theme.libraries.yml]global-js: version: 1.0 js: assets/js/main.js: {} dependencies: - core/jquery - core/once
[main.js]
(function ($, Drupal, once) { Drupal.behaviors.myThemeOrModule = { // Both single or multiple elements is fine. $(once('my-unique-once-id', '.selector', context)).addClass('my-class'); // Multiple elements. $(once('my-unique-once-id', '.selector', context)).each(function(index, element) { $(element).addClass('my-class'); }); // OR use native once's return array => forEach() but note you that can't use jQuery selector extensions like `div:visible`, without calling jQuery like `once([...]).filter(':visible')` once('my-unique-once-id', '.selector', context).forEach(function (element, index) { $(element).addClass('my-class'); }); }; })(jQuery, Drupal, once);
Once API is documented here: https://www.npmjs.com/package/@drupal/once
[do not NPM install it, it is already in drupal core, ass add line via libraries.yml :-) ]