Loosely Coupled: Open Drupal Ajax dialog boxes from React via Drupal Behaviour

03 / Jan / 2023 by Deepali Agarwal 0 comments

Dialogs are a quick and easy way to display additional information without reloading the entire page. Dialog boxes can display just some static text, any node or form of your page, a views page, or any custom markup you’ll feed them.

In order to open some link/node/page in a modal window, you can add the following structure to the link within React:

class="use-ajax" data-dialog-type="modal"

Optionally you can also add data-dialog-options='{“width”:810, “dialogClass”: “modal-react”}’ to style the modal.

And ultimately, the link will look like this:

<a
  href="/admin/content"
  className="use-ajax"
  data-dialog-type="modal"
  data-dialog-options='{"width":810,"dialogClass": "modal-react"}'
>Dialog link</a>

Click on this link, and in most cases it will open the dialog.

But if in case the <a> tag is rendered after a few seconds of page load, within a popup, or after some AJAX call, clicking on the link will do nothing. To overcome this, we will use drupal behaviors to Ajaxify the links.

Drupal has a “behaviors” system to provide a modular and better way for attaching JavaScript functionality to place elements on a page. This Drupal Behavior is the object in JavaScript that Drupal initializes after the page loads and after every AJAX call in DOM.
This drupal behavior can be called from React, let’s see how:

Step 1: Add Drupal Behaviour

First, we will create drupal behavior and write the code to Ajaxify the link within this. For this, create a file js/custom.js and add the following code:

(function ($, Drupal, drupalSettings) {
  Drupal.behaviors.custom_js = {
    ajaxifyLinks: function () {
      jQuery('.use-ajax:not(.ajax-processed)').addClass('ajax-processed').each(function () {
        var ajaxSettings = {
          url: jQuery(this).attr('href'),
          element: this
        };
        Drupal.attachBehaviors(this, ajaxSettings);
      });
    },
    attach: function (context, settings) {
      //Some JS Code
    }
  }
})(jQuery, Drupal, drupalSettings);

Since we are getting new content after the page is loaded, once the new content is loaded, we call Drupal.attachBehaviors() to re-attach any javascript effects to this newly loaded content.

Step 2: Update our libraries

Add custom.js before attaching the react bundle file. This is to ensure our drupal behavior function ajaxifyLinks is available when react is loaded.

react-lib:
  version: 1.x
  js:
    js/custom.js: {}
    js/react-app/dist/app.bundle.js: { minified: true }

Step 3: Call drupal behavior from react

Drupal.behaviors is a global variable that can be used directly within the React app. custom_js is the behavior name we created in the custom.js file, and ajaxifyLinks is a function within that file.

Drupal.behaviors.custom_js.ajaxifyLinks();

Call this after new content is loaded like in the below example link will be rendered after 2s, and drupal behavior will be called after that.

import React, { useState, useEffect } from "react";

const App = () => {
  const [timer, setTimer] = useState(false);

  useEffect(() => {
    setTimeout(() => {
      setTimer(true);
    }, 2000);
  }, [])

  useEffect(() => {
    Drupal.behaviors.custom_js.ajaxifyLinks();
  }, [timer]);

  return (
    <>
      {timer && <a
        href="/admin/content"
        className="use-ajax"
        data-dialog-type="modal"
        data-dialog-options='{"width":810,"dialogClass": "modal-react"}'
      >Dialog link</a>}
    </>
  )
}
export default App;

Read More: Loosely Coupled: Pass data to React app via drupalSettings

Click on the link now, and it will open the dialog.

Optional: Passing parameters

Parameters can also be passed from react to drupal behaviors, like for example if we need to pass parent class from react, we can do so:

Drupal.behaviors.custom_js.ajaxifyLinks('.parent-class');

And can access it within drupal behaviors like so:

(function ($, Drupal, drupalSettings) {
  Drupal.behaviors.custom_js = {
    ajaxifyLinks: function (parentClass) {
      console.log(parentClass);
    },
    attach: function (context, settings) {
      //Some JS Code
    }
  }
})(jQuery, Drupal, drupalSettings);

Note: If any changes are not reflected on page refresh, try clearing the browser or Drupal cache or unchecking “Aggregate JavaScript files” from /admin/config/development/performance.

More on Ajax Dialog boxes.

FOUND THIS USEFUL? SHARE IT

Leave a Reply

Your email address will not be published. Required fields are marked *