Using external JS libraries in our Drupal 8 module

And doing it right

This article was originally posted at Manatí

In order to do this in Drupal 7 we use the libraries module. For Drupal 8, this keeps being the right way to do it; however, this module is in a huge change process and it's not totally well documented, that's why making this the first time is a real challenge.

For this post, we're going to use the Chart.js library in a custom block. First thing we need to do is downloading and installing libraries module. Once done that, according to the documentation we need to check if there's a definition for the library we want to use in the libraries registry; if it exists and works for us, we save one step. If it doesn't exist (that was my situation), we need to create it (and contribute it back to the community of course). To do that, we have to create a json file with our library definition in the folder public://library-definitions. For our case this file will be named chart.js and will have this content:

{
  "name": "Chart.js",
  "type": "asset",
  "vendor url": "http:\/\/www.chartjs.org",
  "download url": "https:\/\/github.com\/chartjs\/Chart.js\/releases\/latest",
    "variants": {
        "minified": {
            "js": {
                "Chart.min.js": "Chart.min.js"
            }
        }
    },
    "js": {
        "Chart.js": "Chart.js"
    },
    "version_detector": {
        "id": "line_pattern",
        "configuration": {
            "file": "Chart.js",
            "pattern": "\/Version: ([0-9a-zA-Z\\.-]+)\/"
        }
    }
}

In this file, we write the library human name, library type (asset), and some other library information.

Please remember to contribute the file through the issue queue once you have tested it so that other people can benefit from it.

The next step is to download the library and place it in the right folder; it's in sites/all/assets/vendor/chart_js for our case. There, we should place Chart.js and Chart.min.js

Of course, in order to use that library, we need a custom js file; so, we create one inside a js folder (only for order) with the name we want. For this post, we're following Chart.js basic example; so, our file will be named demo_chartjs.js and will have this:

(function ($, Drupal) {
  Drupal.behaviors.demoChartJsDemoChart = {
    attach: function (context, settings) {
      var ctx = document.getElementById("myChart");
      var myChart = new Chart(ctx, {
        type: 'bar',
          data: {
            labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
          datasets: [{
            label: '# of Votes',
          data: [12, 19, 3, 5, 2, 3],
          backgroundColor: [
        'rgba(255, 99, 132, 0.2)',
          'rgba(54, 162, 235, 0.2)',
          'rgba(255, 206, 86, 0.2)',
          'rgba(75, 192, 192, 0.2)',
          'rgba(153, 102, 255, 0.2)',
          'rgba(255, 159, 64, 0.2)'
        ],
          borderColor: [
        'rgba(255,99,132,1)',
          'rgba(54, 162, 235, 1)',
          'rgba(255, 206, 86, 1)',
          'rgba(75, 192, 192, 1)',
          'rgba(153, 102, 255, 1)',
          'rgba(255, 159, 64, 1)'
            ],
          borderWidth: 1
          }]
          },
          options: {
            scales: {
              yAxes: [{
                ticks: {
                  beginAtZero:true
                }
              }]
            }
          }
      });
    }
  };
})(jQuery, Drupal);

There are no differences in the way javascript works in Drupal 8 in comparison with Drupal 7. If you want, you can check out the documentation.

For Drupal 8, the only stuff you can attach to any render array are libraries, so we need to define a library. To do that, according to the official documentation we need to create a .libraries.yml file. Since our module is named demo_chartjs, this file will be named demo_chartjs.libraries.yml and have this content:

demo_chartjs:
  version: 1.x
  js:
    js/demo_chartjs.js: {}

Next, we need to create a template to render the necessary markup for our chart. So, we're going to implement hook_theme in the .module file:

/**
 * Implements hook_theme().
 */
function demo_chartjs_theme() {
  return [
    'demo_chartjs_demo_chart' => [
      'variables' => [],
    ],
  ];
}

And add our template file in a templates folder inside our module. That file will be named demo-chartjs-demo-chart.html.twig and have this content:

{#
/**
 * @file
 * Template file for demo_chartjs_demo_chart.
 */
#}
<canvas id="myChart" width="400" height="400"></canvas>

Now, the only pending thing is to create our block; so, let's create a file DemoChartJs.php in src/Plugin/Block and place this content there:

<?phpnamespace Drupal\demo_chartjs\Plugin\Block;use Drupal\Core\Block\BlockBase;
use Drupal\Component\Utility\Xss;/**
 * Provides a 'DemoChartJs' block.
 *
 * @Block(
 *  id = "demo_chart_js",
 *  admin_label = @Translation("Demo chart js"),
 * )
 */
class DemoChartJs extends BlockBase {/**
   * {@inheritdoc}
   */
  public function build() {
    $build = [];
    $build['chart'] = [
      '#theme' => 'demo_chartjs_demo_chart',
      '#attached' => [
        'library' => [
          'libraries/chart_js',
          'demo_chartjs/demo_chartjs',
        ],
      ],
    ];return $build;
  }}

The most important part of that file is the build function; there, we're instructing Drupal to use the theme demo_chartjs_demo_chart previously defined as the rendering of our template. We're also attaching two libraries:

  • libraries/chart_js: Chart.ks library. Since this is an external library; they are always registered as part of the libraries module.
  • demo_chartjs/demo_chartjs: Our libary as defined in .libraries.yml file. This one includes only our js file.

With all the previous stuff done; it's time to test our block. Go ahead and place it in the site and you should have a pretty chart as shown in the header image of this post.

Disclaimer: libraries module is in continous development so some things could change; however, the general concepts shown here I think will remain the same.

I hope this be useful for you.

 

 

 

Tags:
Submitted by kporras07 on