How to Attach Inline JS in Drupal 9 ๐Ÿ’ป

How to Attach Inline JS in Drupal 9 ๐Ÿ’ป

Part 1 of Drupal Migration Series

ยท

5 min read

Hey Everyone ๐Ÿ™‹,

This is Sohini Ghosh. I am a Front End Developer and I am really excited to start my journey on HashNode. โค๏ธ Here's what I can offer and why so !!

Few months ago, when I started migrating our Drupal 7 site to Drupal 9, I found out there were lot of things that were not readily available on internet or on Drupal documentation . So for most of them I had to figure out myself how to make that work.

And this is what I am gonna do here, share my two cents on things that caused me trouble while migrating Drupal to version 9, through a series of blogs in hope to help other Drupal developers who are facing or will face the same problems that I did. So starting off with the first part of the Drupal Migration Series - 'How to Attach Inline JS in Drupal 9' Let's go !! ๐Ÿ™Œ

How to Attach Inline JS in Drupal 9

Inline JS is a snippet of JS that needs to be added to a particular page inline. In Drupal 7, we used drupal_add_js() function to add inline JS from a PHP file.

drupal_add_js('jQuery(document).ready(function () { alert("Hello!"); });', 'inline')

With drupal_add_js() function, we could specify four ways to attach JS to a particular page via four parameters-

  • file to add reference to a JS file to the page
  • external to include an external JS file
  • settings to store variables in Drupal's storage of global settings
  • inline to add JS snippets to a page

But in Drupal 8, the concept of attaching JS via drupal_add_js became obsolete and library API came into picture. Now for both 'file' ,'external' and 'settings' case, we can use the library API to define a library file including the relevant JS files to the library and attach the library to a render element's ['#attached']['library'] array, or via hook_page_attachments() in PHP file.

*.library.yml file to define library-

cuddly-slider:
  version: 1.x
  js:
    js/cuddly-slider.js: {}
  dependencies:
    - core/jquery

Attaching library to the php file-

$build['#attached']['library'][] = 'fluffiness/cuddly-slider';

Here, $build is a render element . 'fluffiness' is the module name and 'cuddly-slider' is the library key name.

But the thing is, Drupal has not specified any API yet to add inline snippets of JavaScript to the page. ๐Ÿ˜“ So how do we add inline JS in Drupal 9 then? I used the following method. Suppose we have an inline JS like this in one of our PHP file in a module named example-

drupal_add_js('jQuery(document).ready(function () { alert("Hello!"); });', 'inline')

We create a new JavaScript file , add the JS snippet in that file and keep the JS file inside JS folder. the JS file looks like this. example.js -

jQuery(document).ready(function () { alert("Hello!"); });

Next we include this JavaScript file in the example.libraries.yml file -

example-js:
  version: 1.x
  js:
    js/example.js: {}
  dependencies:
    - core/jquery

And finally we attach the library in the PHP file in place of drupal_add_js.Here's how-

$build['#attached']['library'][] = 'example/example-js';

And we are done !! Sure that involved quite some steps but not so tough, right?

Well, the trouble is not over yet !! Guess what would we have done , had the Inline JS consisted of some dynamic data like the following, instead of static data that we just saw?

$message = !empty($_GET['start']) ? $_GET['start'] : 0;
drupal_add_js("jQuery(document).ready(function(){" .     
               "localStorage.setItem(\"{$form_state['storage']['user']}\",window.location.href);" 
              "localStorage.removeItem(\"awaitResExpired-{$message}\");" .
                     "});", "inline");

As you can see, there are two dynamic part included in inline section here, one is $message and another is $form_state['storage']['user']. So we can not just handpick the entire inline part as it is and keep that in another JS file like we did in the previous example. Then how can we pass the variables from PHP to JS file ? This is what we do. We store the variables in Drupal's global storage of JavaScript Settings and we access them from JS file using drupalSettings. Basically we use the library API available for 'settings' parameter in drupal_add_js for this problem.

You can check the Drupal documentation for drupalSettings here-

https://www.drupal.org/docs/creating-custom-modules/adding-stylesheets-css-and-javascript-js-to-a-drupal-module

This is how the PHP file looks now-

$message = !empty($_GET['start']) ? $_GET['start'] : 0;
$data = [ 'message' => $message,
                 'user' => $form_state->get('user')
                    ];
$form['#attached']['library'][] = 'example/example-js';
$form['#attached']['drupalSettings']['example']['exampleJs'] = $data;

We create another JavaScript file and add the inline JS with `drupalSettings'-

jQuery(document).ready(function(){
                   localStorage.setItem(drupalSettings.example.exampleJs.user, window.location.href);
                   localStorage.removeItem('awaitResExpired-' + drupalSettings.example.exampleJs.message);
                                    });

Finally the example.libraries.yml file-

example-js:
    version: 1.x
  js:
    js/example.js: {}
  dependencies:
    - core/jquery
    - core/drupal
    - core/drupalSettings

Now we are done. There are also some other ways you can address this problem like using Inline module or using .twig template, but according to the documentation they are not recommended. This worked for me pretty fine and hopefully will for you too. You can checkout the complete working code here-

https://github.com/Sohini18/Drupal_Migration_Series

Also here are some of the resources you can definitely refer to that helped me a lot.

Hope you liked this article. If you did, please please don't forget to put a โค๏ธ. And guess what, in the next part of the Drupal Migration Series, I will address another problem that bugged me a lot i.e. How to attach your library in Drupal 9 if there is no render element available already? Stay Tuned !! ๐Ÿง˜

Happy Migrating

ย