6

I've read through a bunch of material about using JS in Drupal 8 theming and module development, but did not come away with an understanding of the most straightforward way to routinely add things likes GSAP animations and interactive D3 charts to individual nodes.

Each piece of custom JS will only ever be needed on one page. Over time the site may grow to include 10s or even 100s of such pages.

From reading the module development documentation, creating a custom module and adding each JS file to the myModule.libraries.yml with logic to load each on only one page based on id would work, but before I start down that path I thought I'd ask if there is some other way to do this.

19

Following Steps will make working with External JavaScript libraries in Drupal 8 absolutely clear (including how to conditionally load it in specific pages):

Step 1: Place the JavaScript file in your theme or module inside a folder called js. After this step your folder structure must look like :

my-theme/js/my-script.js

Step 2: If your theme already has a my-theme.libraries.yml file open it, if not create it.

In Drupal 8 Libraries are simply collections of CSS or JS files bundled together under a uniquely identified library name.

In this step we need to include the JS file that we created in step 1 in our library. we do it by adding following lines of code in our my-theme.libraries.yml file.

my-library:
  js: 
    js/my-script.js: {}

Now we have an asset library called my-theme/my-library which can be loaded to our site in several ways.

Step 3: Final step is to load the library in our site. This can be done in 4 specific ways:

Way 1: Attach library globally via theme-name.info.yml file

Libraries can be specified in the theme-name.info.yml file by adding it to the libraries property, like this:

name: my-theme
type: theme
description: my theme
package: other
core: 8.x
libraries: 
  - my-theme/global-effects
  - my-theme/my-library

base theme: stable

Any libraries specified here in the themename.info.yml file will be made available on evey page.

Way 2: Using hook_page_attachments_alter in theme-name.theme file.

Following lines of code will attach our library only to the node listing page.

function mytheme_page_attachments_alter(&$page){
  $path = $current_path = \Drupal::service('path.current')->getPath();
  if($path == '/node') {
    $page['#attached']['library'][] = 'my-theme/my-library';
  }
}

Way 3: Another useful way to conditionally add a library is by using a preprocess function like hook_preprocess_page().

Here's another example of restricting our asset libray to the front page

function mytheme_preprocess_page(&$variables){
  if ($variables['is_front'] == TRUE) {
    $variables['#attached']['library'][] = 'my-theme/my-library';
  }
}

Way 4: Asset libraries can also be attached from within a Twig template using the attach_library function. Anytime that template is used the corresponding library will be attached in accordance with any template-specific conditions.

In order to see this in action, we need to create or modify a template in our theme. In this example let us modify node.html.twig template to attach our library only if node.id == 1 with following lines of code

{% if node.id == 1 %}
  {{ attach_library('my-theme/my-library') }}
{% endif %}

With this in place, visiting node 1 in our site, we will be able to see our library in action.

  • Great write up. I found this very helpful. Many thanks. – Will Tate Sep 11 '18 at 15:42
  • To be noted the Drupal 8 approach is librariy based. If you need to load a css/js file on a specific page, you have to create a library for that file. – augusto Jun 20 at 9:21
  • Worked for me. Thanks! – mrlexington Aug 9 at 15:45
2

See: https://www.drupal.org/developing/api/8/assets

Quote from page:

Attaching a library to page(s)

Depending on which assets you need to have loaded, you'll want to attach the corresponding asset library in a different way. After all, some asset libraries are needed on all pages, others only very rarely, and yet others on most, but not quite all.

But what matters most is that we don't decide whether to attach a library based on which page we're on (i.e. which URL or route), but based on which things are visible on the page: if a page contains a '#type' => 'table', a '#type' => 'dropbutton' and a '#type' => 'foobar', then we'll only load the libraries associated with each of those '#type's. But we're not limited to '#type' only: perhaps we want to load a certain asset library only for a certain instance of a '#type'. In that case, we just attach it to the render array of that instance.

Of course, very rarely, there is a valid reason to actually load a certain asset on all pages (e.g. some analytics JavaScript that tracks page loads), regardless of the "things" on a page.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.