2

When implementing a Drupal behavior, a selector can use the 'context' parameter to let the behavior only apply to new elements. On page load the context is the document (I think), on ajax load it is the new ajax content.

Drupal.behaviors.my_behavior = {
  attach: function attach(context, settings) {
    $('.my-selector', context).each(function() {..});

Until now I thought that this alone is sufficient to make sure the behavior runs only once per element.

But in Drupal core and contrib, I see a lot of cases where context is used in combination with .once(), like so:

Drupal.behaviors.my_behavior = {
  attach: function attach(context, settings) {
    $('.my-selector', context).once(function() {..});

Is this ever necessary? Or is 'context' sufficient? And if it is not necessary, why is it used so much in core and contrib?

If it is necessary, does this also apply to click handlers? E.g. would the following cause duplicated click handlers in some cases?

Drupal.behaviors.my_behavior = {
  attach: function attach(context, settings) {
    $('.my-selector', context).click(function() {..});

NOTE: A secondary question would be if 'context' is still necessary if we use 'once()'. My answer to this is: Even if it is not necessary, it is still a good idea because it reduces the search space for jQuery on subsequent calls, thus reducing client-side energy consumption.

NOTE: I encountered this question on D7, but it might equally apply to D8.

4

The short answer, is 'yes'. The longer answer is that if all developers properly used the API, you would likely not have to use $.once(). However, you cannot count on developers using the API correctly, so $.once() insulates you against that.

This is because the context passed to Drupal.behaviors is the part of the DOM passed by developers when calling Drupal.attachBehaviors(). However, a lot of the documentation on the web has not specifically stated this, resulting in many developers not passing any value to Drupal.attachBehaviors(). If no value is passed, then the entire DOM becomes the context. This means that your code could be passed through your handler multiple times. This is why $.once() is used.

| improve this answer | |
  • Thanks! So, bonus questions: 1. Is this only about "wrong" usage of Drupal.attachBehaviors(), or could "legitimate" usage cause the same problems? E.g. via the regular server-side AJAX API? 2. Does this apply to click handlers as well? (answer: yes) – donquixote Jul 30 '19 at 22:02
  • I wouldn't say it's wrong, since it can be done and is. The key here is not whether developers should be passing part of the DOM, it's that it's been explicitly decided that you cannot count on developers doing so, and $.once() is the APIs method of ensuring consistency. – Jaypan Jul 30 '19 at 22:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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