0

I'm facing a weird issue where a JS file attached via the Javascript API does not work properly. I couldn't really pin down why it isn't working by the JS file consists of a few event listeners which get attached to DOM elements and it looks like this:

(function ($, Drupal) {
  Drupal.behaviors.basics = {
    attach: function (context, settings) {
      if (context !== document) {
        return;
      }

     initPublicationsAccordion($)
     initBackground($)
     initNavbarFix($)
     initMobileNav($)
     initAuthorsDropdown($)
     setTimeout(() => initCarousel($), 500) // this fixes it
    }
  };
})(jQuery, Drupal);

and the corresponding *.libraries.yml file:

global:
  css:
    theme:
      css/main.css: {}
  dependencies:
    - core/drupal
    - core/jquery
    - drulma/bulma
    - drulma/mainjs

...

mainjs:
  js:
    js/main.js: {}
  dependencies:
    - core/drupal

There are no errors in the console, but I noticed I can make it work by wrapping the functions in a setTimeout. I would appreciate if anyone has an idea?

0

1 Answer 1

1

You are firing your event on document context, which happens only once (basically same as old school $(document).ready()). But a major point Drupal behaviors is that they are fired every time when somehing is added to the DOM, even when added with Ajax. (core's BigPipe might add blocks with Ajax, this module is enabled by default)

So instead of the one-shot

  Drupal.behaviors.basics = {
    attach: function (context, settings) {
      if (context !== document) {
        return;
      }
      ...do stuff

target the specific DOM nodes, e.g. if your carousel has a container
<div class="my_fancy_carousel">...</div>
attach the behavior to its class:

  Drupal.behaviors.my_fancy_carousel  {
    attach: function (context, settings) {
      $('.my_fancy_carousel', context).once('init_my_fancy_carousel').each( function() {
        ...do stuff...

Also notice the .once('my_unique_identifier') part which makes sure your functions don't trigger repeatly on the same DOM node

5
  • If you use .once() add core/jquery.once to the list of dependencies for your library.
    – sonfd
    Jan 27, 2021 at 21:17
  • You guys are legends, it seems like it is working with a quick look. Will confirm.
    – supersize
    Jan 28, 2021 at 8:07
  • Yeah it is working. @Hudri question, do I need to add a new Drupal.behaviours for each event listener I'm attaching or can I wrap this in one? Can you assist me once more with this question?
    – supersize
    Jan 28, 2021 at 8:14
  • You can add everything into a single behavior wrapper, but use different "once's" for different jobs, e.g. use $('.carousel-selector', context).once('my_carousel') and a separate $('a.lightbox', context).once('my_lightbox')
    – Hudri
    Jan 28, 2021 at 8:20
  • Thanks man, very helpful. Is the label in the once method used somewhere else, or has some other advantages one can use?
    – supersize
    Jan 28, 2021 at 9:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.