Search code examples
ruby-on-railswebpackwebpacker

Chart is not defined in a Rails 6 view page with webpacker


I'm trying to figure out the right way to use a Chart from chart.js in a Rails 6 app using webpacker. I would like my chart generation javascript code to remain in the page since I'll be dynamically generating it from the view.

I started with

yum add chartjs

then added to the application pack (and javascript_pack_tag is in my application.html.erb)

// app/javascript/packs/application.js
import Chart from "chartjs";

And then, in a view I try and use that library:

  <div class="row">
    <div class="col">
      <canvas id="backlog-chart" width="100%" height="400px">
      <script>
        var ctx = document.getElementById('backlog-chart').getContext('2d');
        new Chart(ctx, { ...

This fails with an Chart is not defined javascript error.

Things I've tried:

  1. the require("chartjs") form of including the library in application.js seems to have no impact one way or the other.
  2. I tried adding to config/webpack/environment.js to the ProvidePlugin object with Chart: "chartjs/chart.js" but no changes.
  3. And I've tried adding import Chart from "chart.js" directly to the <script> section in the view but this fails with a "import only allowed in module" error on the browser.

My javascript skills have definitely not kept up with the last couple years of new technologies so any suggestions on the right way to do this would be appreciated.


Solution

  • You can't use Chart in a script in your HTML body because Chart hasn't been globably defined. You could import the chart.js javascript by embedding the script tag, and then Chart would be available. But you said you wanted to use Webpacker, so...

    Include your chart definition in your application.js, rather than in the script tag.

    // app/javascript/packs/application.js
    import Chart from "chartjs";
    
    var ctx = document.getElementById('backlog-chart').getContext('2d');
    var myChart = new Chart(ctx, {...});
    

    This will target that canvas in your HTML:

    <canvas id="backlog-chart" ... />