16

I have a behavior that adds on to some checkboxes.

(function($) { 
  Drupal.behaviors.mymodule = {
    attach: function (context, settings) {

      $('.skip-line', context).on('change', function(){
        // some code
        if ( confirm(Drupal.t('Apply to all languages?')) ) {
          // applying...
        }
      });
    }
  };
})(jQuery);

It works very well, but checkboxes are in AJAX-loaded part. If I reload that part of the form, clicking on them makes confirmation popup twice. Now, I know I can test inside function if it's the first time in a row it's called, but I would prefer to make sure it is added to my element only once, and thus called only once. How can I do that?

5 Answers 5

26

The once() function will help with that,e.g.

(function($) { 
   Drupal.behaviors.mymodule = {
    attach: function (context, settings) {

      $('.skip-line', context).once('mymodule').on('change', function(){
        // some code
        if ( confirm(Drupal.t('Apply to all languages?')) ) {
          // applying...
        }
      });
    }
  };
})(jQuery);

One of the many references

2
  • 4
    Thanks. Worked like a charm. I guess that's one of these moments when I simply fail to ask Google properly. I asked about preventing twice and preventing multiple. If only I have asked about doing it once...
    – Mołot
    Nov 8, 2013 at 11:47
  • 3
    @Mołot But thanks to your comment being indexed, I found it when I searched for prevent multiple :-D
    – frazras
    Oct 21, 2019 at 14:24
8

You need to use the once() function to achieve this. From this page

Drupal.behaviors.myModule = {
  attach: function (context, settings) {
    $('element', context).once('myModule', function () {
     // any behavior is now applied once
    });
  }
};

The string "myModule" passed to the function is set as a marker on the elements matching the jQuery selection, so the next time once is called it ignores them. Do not use the same string if you call the once function multiple times for different purposes, otherwise you may defeat its purpose.

1
  • Thank you for your explanation :) Accepted Clive's answer as his code worked for me directly and your didn't, but I like your description better.
    – Mołot
    Nov 8, 2013 at 11:50
5

you can also do this too:

(function ($, Drupal, drupalSettings) {
    'use strict';
Drupal.behaviors.someThing = {
        attach: function (context) {
            if (context === document) {
               console.log('called inside'); // Once <-- 
            }
            console.log('called outside'); // can be manny manny  <-- 
         },
    };
})(jQuery, Drupal, drupalSettings);
1
  • Great this works for me May 8, 2020 at 10:23
4

Here's an example that expands on frazras answer:

var searchPagesFoundationAccordionInit = false;
Drupal.behaviors.searchPagesFoundationAccordionInit = {
  attach: function (context, settings) {
    // Attempt to resolve behavior being called multiple times per page load.
    if (context !== document) {
      return;
    }
    if (!searchPagesFoundationAccordionInit) {
      searchPagesFoundationAccordionInit = true;
    }
    else {
      return;
    }

    // Check if component exists.
    if ($('.view-style--search-page .search-section__sidebar .accordion').length > 0) {
     // Code here.
    }
  }
};
2
  • This solution worked for me. I don't need to link some element with action. I have to run just a function. Drupal.behaviors.checkOnce = { attach: function (context, settings) { if (context === document) { check(); } function check() { //code } } }; In this case the check() function will run only once, when context will be a document Apr 30, 2020 at 14:42
  • life saver 2023
    – cen
    May 17, 2023 at 16:25
2

here is another way to have a function that runs once:

(function($, Drupal) {

  var initialized;

  function init() {
    if (!initialized) {
      initialized = true;
      // Add your one-time only code here
    }
  }

  Drupal.behaviors.someKey = {
    attach: function() {
      init();
    }
  };

}(jQuery, Drupal));

Source: https://www.drupal.org/forum/support/module-development-and-code-questions/2018-06-15/run-js-funtion-once-not-attach-once#comment-12654121

1
  • 1
    Thank you for sharing this solution. Since I had a longer code inside the behavior block, this was by far the best one for keeping it organized and clean. Dec 23, 2020 at 20:41

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.