logo
Submitted by Mikhail Ismajlov on Tue, 09/10/2019 - 10:10

To get started, let's get back to how to include custom javascript files to our theme. In the .libraries.yml file, you need to include js:

global-styling:
  version: 1.x
  css:
    theme:
      css/style.css: {}
      css/print.css: { media: print }
  js:
    js/custom.js: {}
  dependencies:
    - core/jquery
    - core/jquery.once

It is important to follow the indentation so that it is in two spaces. So, we have included the js/custom.js file. But this is not enough for jQuery to work for us. The fact is that the Drupal core does not require jQuery and jQuery does not include. It must be included separately:

dependencies:
  - core/jquery

We will also use jQuery.once(), this is a separate plugin for jQuery, in order to attach events and methods to the selector only once.

dependencies:
  - core/jquery
  - core/jquery.once

The fact is that we will write javascript code that will be called by Drupal several times for different events. Therefore, we will need this .once() method.

Now let's add some code to the custom.js file:

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
      $(context).find('.click-me').once('myCustomBehavior').click(function () {
        alert('Hello, World!');
      });
    }
  };
})(jQuery);

Let's take it in order.

(function ($) {
 
})(jQuery);

We wrap jQuery code in this construct because jQuery in Drupal runs in .noConflict () mode. This is necessary in order to use the dollar sign $, and this did not conflict with other javascript frameworks Prototype, MooTools. It is unlikely that you will have to meet with these frameworks; jQuery has tightly taken a leading position. But you will have to wrap all jQuery code in this construct.

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
 
    }
  };
})(jQuery);

So we come to the behavior. If you write jQuery code in Drupal, you need to first wrap it in function ($), and secondly in behavior. The behavior name must be unique, in our example myModuleBehavior, but you need to write a name for each behavior:

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
 
    }
  };
 
  Drupal.behaviors.productPageBehavior = {
    attach: function (context, settings) {
 
    }
  };
})(jQuery);

Use camelCase to name the behavior. Behavior is called when the page loads, for every AJAX request. Thus, when new content is uploaded to the site and embedded in the structure of the existing site, the code from behavior is called, each time. This is significantly different from:

$(document).ready(function () {
  // Do some fancy stuff.
  // Do not use such code in Drupal 8 (and in Drupal 7 too).
});

which is called only once upon loading the page.

If you started using behaviors and noticed that you have strange events with the site, for example, through jQuery, a block is added several times:

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
      // Behavior вызывается несколько раз на странице, не забывайте использовать функцию .once().
      $('.inner').append('<p>Test</p>');
    }
  };
})(jQuery);

For each ajax request, you will add another Test paragraph. Therefore, you need to add the .once() function:

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
      // Behavior is called several times on the page, do not forget to use the .once () function.
      $('.inner').once('add-paragraph').append('<p>Test</p>');
    }
  };
})(jQuery);

Another feature of behavior is the context variable. Each time new content is added to the site when the page is loaded or through ajax, then all new content is in the context variable. Thus, we do not need to go through the entire DOM tree, after each ajax request, to attach the event to the selector. Just context is enough:

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
      // Behavior is called several times on the page, do not forget to use the .once () function..
      $(context).find('.inner').once('add-paragraph').append('<p>Test</p>');
    }
  };
})(jQuery);

Now the paragraph is written in the correct Drupal style. Of course, you can use the old entry with document.ready (), but then it will only work once and slower than through behavior.

If you have any questions about jQuery/javascript or suggestions for additional theme, write in the comments.