I thought using a behavior was like using
jQuery(document).ready(function ($), so the code would only be
executed when the DOM was fully loaded, and don't understand why it is
being called for five different contexts.
No. If it would be like this, behaviors would be pointless.
- Behaviors are tied to a single DOM node, because in Drupal you don't know when this DOM node is rendered/injected in the page (remember BigPipe, Ajax Views, Ajax shopping carts, etc).
- Behaviors are fired first time after DOM ready, AND potentially very often afterwards when new partials are injected into the DOM. To avoid duplicating event listeners on pre-existing, older nodes use the
once-function.
- The
context just makes it faster to de- and re-attach the behaviors, if you omit the context, any injection of a DOM node has to search the entire document for potential behaviors, and not just inside the context of the newly injected partial.
- The equivalent of
$(document).ready() would be calling $(document, context).once() inside a behavior, because the document-context is passed only once.
Your loop code would look like this:
Drupal.behaviors.myCustomBehavior= {
attach: function (context, settings) {
$('.section-wrapper', context).once('myCustomOnceId').each( function(index) {
$(this).addClass('foo');
});
}
};
So, e.g. if your <div class="section-wrapper"> is inside a row of an infinite scroll view, every <div> will get exactly one foo class, no matter when it is loaded.
Continuing the example above with the infinite scroll view and the "foo" class, after 2 Ajax injections...
...without using a behavior, you would end up with something like
<div class="section-wrapper foo"></div><div class="section-wrapper"></div><div class="section-wrapper"></div>
...using a behavior without once, you would end up with something like
<div class="section-wrapper foo foo foo"></div><div class="section-wrapper foo foo"></div><div class="section-wrapper foo"></div>