Drupal javascript events on AJAX modal

Table of contents

In Drupal, you can very easily create dialog boxes of three different flavors : they can be simple dialog boxes but also modals or even displayed off-canvas. Despite the title, this article will talk about event on dialogs, not just modal once. For more information about it, you can refer to this overview documentation about dialog boxes in Drupal.

Drupal dialog types example (dialog, modal, off-canvas)
Drupal dialog types example (dialog, modal, off-canvas)

In your custom modules or theme, you might want to listen to the opening / closing of dialog boxes and react to it. For example - on a client website - I had to read/write a cookie to determine if a user had seen or not a particular popup. Therefore, I needed a way to react to the opening of a modal, but also to determine which one it was in particular.

Although the modals themselves in Drupal are (yet) provided by jQuery UI, Drupal encapsulates it in it's own code and offers a few events you can react to :

  • dialog:beforecreate
  • dialog:aftercreate
  • dialog:beforeclose
  • dialog:afterclose

All of them are triggerred on the window object from misc/dialog.js file (you can read it's commented source code at /core/misc/dialog/dialog.es6.js for details).

In essence, your own custom javascript reacting to those events will set place in your custom module or theme, and will look something like :

1
2
3
4
5
6
7
8
9
10
11
(function ($, Drupal) {
  Drupal.behaviors.custom_behavior = {
    attach: function (context) {
      $(window)
        .once('custom-behavior')
        .on('dialog:beforecreate', function () {
          console.log('The most simple use case !');
        });
    }
  };
})(jQuery, Drupal);

More advanced scenarios

Let's see below some more detailled and advanced use cases. With these tricks, you will be able to :

  • determine if your dialog box is a modal, an off-canvas or a simple dialog
  • specifically target only modals, or off-canvas, or simple dialogs
  • specifically target a particular dialog by passing a specifically recognizable option
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
(function ($, Drupal) {
  Drupal.behaviors.custom_behavior = {
    attach: function (context) {
      $(window)
 
        // Supposes "core/jquery.once" as a dependency in your *.libraries.yml
        .once('custom-behavior')
 
        // Callback registered on event in it's simplest form.
        .on('dialog:beforecreate', function () {
          console.log('The most simple use case!');
        })
 
        // Multiple event listeners can also be passed as an associative object.
        .on({
          'dialog:aftercreate': function () {
            console.log('Dialog is now opened!');
          },
 
          /**
           * The callback can also accept parameters.
           * @param event
           *   The event triggered itself
           * @param dialog
           *   The jqueryUI polyfilled HTML5 dialog element. This class has various methods
           *   to open / close the popup, etc… (@see core/misc/dialog/dialog.es6.js)
           * @param $element
           *   The dialog element itself, as a jQuery element.
           * @param settings
           *   The dialog settings (default + custom merged).
           */
          'dialog:aftercreate': function (event, dialog, $element, settings) {
 
            // NOTE: doSomething has been passed as a dialog option.
            if ($element.dialog('option', 'doSomething')) {
              console.log('Dialog with doSomething option has been opened!');
            }
 
            // NOTE: in both 'beforecreate' and 'aftercreate' events, we have the settings
            // available, so this is equivalent to the code above:
            if (settings.doSomething) {
              console.log('Equivalent doSomething check. You still should prefer option 1.');
            }
 
            // Specifically target only modals.
            if ($element.dialog('option', 'modal')) {
              console.log('This is a modal element.');
            } else {
              console.log('This can be either a dialog or an off-canvas element.');
            }
 
            // Specifically target only off-canvas dialogs.
            // NOTE: needs "core/drupal.dialog.off_canvas" as a dependency in your *.libraries.yml
            if (Drupal.offCanvas.isOffCanvas($element)) {
              console.log('This is an off-Canvas element.');
            }
          },
 
          // NOTE: beforeclose and afterclose events do not have "settings" last parameter given to the callback.
          'dialog:afterclose': function (event, dialog, $element) {
            // NOTE: nodeId has been passed as a dialog option.
            console.log('The dialog for node ' + $element.dialog('option', 'nodeId') + ' as been closed by user.');
          }
        });
    }
  };
})(jQuery, Drupal);

If you have some other usecases, leave a comment below :)

Add new comment

Your name will be publicly displayed along with your comment.
Your email will be kept private and only used to notify you.
On internet, you can be who you want. Please be someone nice :)