Work In Progress

This book is currently work in progress. Some sections are not yet written. Thank you for your understanding!

Passing data from the backend to the JavaScript on the page

Back in the early Joomla 3 days we used to send data to the frontend JavaScript code using inline JavaScript fragments. For example:

JFactory::getDocument()->addScriptDeclaration(<<<JS
  var comExampleSomething = "{$foobar}";
JS
);

On the client side (JavaScript) you'd just use this JavaScript variable.

This is bad for a number of reasons. To begin with, the inline script declaration must definitely be parsed before any other code — including JavaScript files — which make use of it. Back when all scripts were loaded in the document's <head> that was a given. However, this code broke spectacularly when met with any plugin or third party solution (such as CloudFlare RocketLoader) which moved the scripts at the bottom of the HTML <body> or lazy-loaded them. There was no guaranteed script execution anymore.

The variable being passed (in our example, $foobar) would have to be properly escaped to make it valid JavaScript or the client-side could break or, worse, we'd introduce a security vulnerability!

Moreover, this solution pollutes the JavaScript global scope and slows down the page as the browser has to stop parsing the DOM and rendering the page to evaluate the JavaScript.

Ever since Joomla 3.5 you had the option to instead push script options through the document:

\Joomla\CMS\Factory::getDocument()->addScriptOptions(
  'com_example',
  [
    'foo' => $foobar,
    'bar' => SOME_CONSTANT,
  ]
);

This embeds a JSON document into the HTML which does not need to be parsed by the browser as JavaScript. Instead, when the core JavaScript loads it will parse it and make it available to our client-side code:

var comExampleOptions = Joomla.getOptions('com_example');
var distance = comExampleOptions.foo * comExampleOptions.bar;

But how can we be sure that our code loads after the core Joomla JavaScript? Well, this is trivial in Joomla 4 and later by using the WebAssetManager and adding core as a dependency. We also need to set our script to have the option "defer": true in our joomla.asset.json file so it loads deferred, i.e. after the browser parses the DOM — just like the core JavaScript does. This way we can be sure that our file executes after Joomla.getOptions is available in JavaScript and we no longer need to add special code to execute our code after the page has finished loading; both conditions are guaranteed.