Script issues when using chart.js in Django

Python 3.12.4
Django 5.1.3

When using chart.js in Django and placing the script in the HTML page I get these weird JS errors. I have included a screen shot below as well as the code below that. I need to point out that it all works perfectly. The chart loads and the data is correct from the view query, no errors other than what I see in VSC on the html page.

I have a query view that generates the data and includes it in a context (normal stuff here) and rendering to an html page with

<canvas id="myChart" class="chart" width="400" height="200"></canvas>

set up and the script at the bottom of the page inside the body. If I hover over each error I see things like:
Property assignment expected.javascript
‘,’ expected.javascript
Type annotations can only be used in TypeScript files.javascript
Declaration or statement expected.javascript

What’s interesting if I take out this line

data: {{ data|safe }},

and replace it with this line with a hard var in it

data: myChartData,

all the errors go away. At first I thought maybe it was something to do with JS linting etc. But seem to not be. I appreciate all help on this. Thank you.

Screenshot of code in VSC with errors.

Copy of script used

<script>
  var config = {
    type: 'bar',
    data: {
      datasets: [{
        label: "Epson NOC Monthly Totals",    // label is what is printed at top of chart in the center
        data: {{ data|safe }},
        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,
      }],
      labels: {{ labels|safe }}
    },
    options: {
      responsive: true
      }
  };

  window.onload = function() {
    var ctx = document.getElementById('myChart').getContext('2d');
    window.myBar = new Chart(ctx, config);
  };

</script>

What makes you think that the errors flagged here are not simply a VSCode JS linting issue? The {{ }} notation is not valid JavaScript and isn’t going to pass.

Also, what is actually rendered and sent to the browser?

Looking at the actual JavaScript code as it has been rendered and sent to the browser would be more helpful in identifying the errors being reported in the browser.

re: JSLint
I did what VSC said to do and installed JSlint and enabled it and that did not fix it. I asked ChatGpt and github copilot and they suggested above.

re: {{ }}
The use of {{ }} is what is used in more than 20 examples for chart.js in Django and is also from official charts site. Also Chatgpt and Gpt4all and github copilot use the same examples.

I did look at chrome dev tools response and because this is not causing an error and my lack of JS knowledge nothing jumped out.

After 6 hours nothing was jumping out at me.

Using the {{ }} is correct. However, it’s not JavaScript syntax, it’s Django Template Language. You shouldn’t expect a JavaScript linting tool to understand text that isn’t JavaScript.

If the code is working, then there is not a problem with the code. Therefore, the problem is with the tool saying that there is an error.

So fundamentally, yes, this is a linting issue, in that you’re expecting a lint tool to process a different language than that for which it is designed.

What’s interesting is one of the suggestions was to put the code in a .Js file and it showed the same errors. So I do think your correct being a linting issue. I will do more troubleshooting based on your suggestions and see what I can find.
I appreciate you’re help as always.
Thank you

Technically, what you should be doing is using the json_script filter to separate your Django-supplied data from the JavaScript code. The data should be rendered into your template, and then your JavaScript code can copy that data into your JavaScript object.

1 Like

This is a good guide to passing your Django data to JavaScript in the template How to Safely Pass Data to JavaScript in a Django Template - Adam Johnson

1 Like

I appreciate all the guidance on this issue but still issues persist.
I see that how I was using chart.js and passing the data was not secure. I have changed my code to fix this but now caused another issue.
According to Django docs json_script is a built in tag. It is part of the security middleware. You need to make sure your settings.py file has ‘django.middleware.security.SecurityMiddleware’, in MIDDLEWARE:

'django.middleware.security.SecurityMiddleware',

and insert one of the following in your HTML page

{% load security %}
or
{% load json_script %}

Either of these cause:
TemplateSyntaxError at /console_app/
‘security’ is not a registered tag library. Must be one of:

Here is my code:

views.py function (partial)

data = {
        'labels': ['Messages', 'Ivanti', 'SolarWinds', 'Control-M', 'TurnOver Log'],
        'values': [53, 6, 27, 42, 100]   
    }
    template = 'console_app/base_console_ap.html'
    return render(request, template, {'chart_data': data})

base_console_ap.html (partial)

{% load security %}
or
{% load json_script %}

<canvas id="myChart" class="chart" width="400" height="200"></canvas>

<script src="{% static 'js/chart.min.js' %}"></script> 

<script>
  const chartData = JSON.parse(document.getElementById('chart-data').textContent);
  const ctx = document.getElementById('myChart').getContext('2d');
  const myChart = new Chart(ctx, {
      type: 'bar',
      data: {
          labels: chartData.labels,
          datasets: [{
              label: 'My Dataset',
              data: chartData.values,
          }]
      },
  });
</script>

<script id="chart-data" type="application/json">
  {{ chart_data|json_script:"chart-data" }}
</script>

This is not correct. Neither of those load directives are needed. Neither is any specific middleware. This is a template filter and operates outside the context of any middleware.

Where are you getting this information?

I got this from the other gentleman that responded to this forum with a link to json_script usage.

Yes reading Django docs it should not be needed, but I tried them anyways. When I remove the tags I do not get the error anymore nor does the chart work.
When I drill down in the response and I see this :

{060B5647-8D4A-4502-8B3E-37EFFED2E86E}

When I hover over the red x i see this:

Uncaught TypeError: Cannot read properties of null (reading 'textContent')

You can see from (script id=“chart-data”) that the data from the view is making it there.

<script>
  const chartData = JSON.parse(document.getElementById('chart-data').textContent);

  const ctx = document.getElementById('myChart').getContext('2d');
  const myChart = new Chart(ctx, {
      type: 'bar',
      data: {
          labels: chartData.labels,
          datasets: [{
              label: 'My Dataset',
              data: chartData.values,
          }]
      },
  });
  
</script>

<script id="chart-data" type="application/json">
  <script id="chart-data" type="application/json">"{\"labels\": [\"Messages\", \"Ivanti\", \"SolarWinds\", \"Control-M\", \"TurnOver Log\"], \"values\": [53, 6, 27, 42, 100]}"</script>
</script>

I have also adjusted the script to make sure the DOM is loading before the script runs

<script>
document.addEventListener('DOMContentLoaded', function () {
    
  const chartData = JSON.parse(document.getElementById('chart-data').textContent);

  const ctx = document.getElementById('myChart').getContext('2d');
  const myChart = new Chart(ctx, {
      type: 'bar',
      data: {
          labels: chartData.labels,
          datasets: [{
              label: 'My Dataset',
              data: chartData.values,
          }]
      },
  });
});
</script>

You’ve got two elements here with the same HTML id attribute. This is an error, the id attribute must be unique on a page.

Hmm, That’s interesting. The code is:

<script id="chart-data" type="application/json">
  {{ chart_data|json_script:"chart-data" }}
</script>

The response is what u pointed out. So I changed it:

<script>
    
  const chartData = JSON.parse(document.getElementById('chart-data1').textContent);

  const ctx = document.getElementById('myChart').getContext('2d');
  const myChart = new Chart(ctx, {
      type: 'bar',
      data: {
          labels: chartData.labels,
          datasets: [{
              label: 'My Dataset',
              data: chartData.values,
          }]
      },
  });

</script>

<script id="chart-data1" type="application/json">
  {{ chart_data|json_script:"chart-data" }}
</script>

and the response still shows the data accurately. Same original error.

<script id="chart-data1" type="application/json">
  <script id="chart-data" type="application/json">"{\"labels\": [\"Messages\", \"Ivanti\", \"SolarWinds\", \"Control-M\", \"TurnOver Log\"], \"values\": [53, 6, 27, 42, 100]}"</script>
</script>

I have used the example that Django docs shows and still same results.

<script id="hello-data" type="application/json">{"hello": "world\\u003C/script\\u003E\\u0026amp;"}</script>

With my changes:

<script id="chart-data" type="application/json">{{ chart_data|json_script:"chart-data" }}</script>

response:

<script id="chart-data" type="application/json"><script id="chart-data" type="application/json">"{\"labels\": [\"Messages\", \"Ivanti\", \"SolarWinds\", \"Control-M\", \"TurnOver Log\"], \"values\": [53, 6, 27, 42, 100]}"</script></script>

This is not what the docs are telling you to use. This is the sample output from having done what the previous sample describes.

The example that you code is the block above that.

{{ value|json_script:“hello-data” }}

It’s that line of code generating the output that you’re quoting above.

Yes only put that there as an example. Of course I changed it as I put below that example.

So I did make another change and it works now.

I added this above the script:

{{ chart_data|json_script:"chart-data" }}

I removed this script from the bottom:

<script id="chart-data" type="application/json">{{ chart_data|json_script:"chart-data" }}</script>

Now Code looks like this :

{{ chart_data|json_script:"chart-data" }}

<script>
  const chartData = JSON.parse(document.getElementById('chart-data').textContent);
  const ctx = document.getElementById('myChart').getContext('2d');
  const myChart = new Chart(ctx, {
      type: 'bar',
      data: {
          labels: chartData.labels,
          datasets: [{
              label: 'My Dataset',
              data: chartData.values,
          }]
      },
  });
</script>

And now the response returned from view is:

<script id="chart-data" type="application/json">{"labels": ["Messages", "Ivanti", "SolarWinds", "Control-M", "TurnOver Log"], "values": [53, 6, 27, 42, 100]}</script>

<script>
  const chartData = JSON.parse(document.getElementById('chart-data').textContent);
  const ctx = document.getElementById('myChart').getContext('2d');
  const myChart = new Chart(ctx, {
      type: 'bar',
      data: {
          labels: chartData.labels,
          datasets: [{
              label: 'Epson NOC Monthly Totals',
              data: chartData.values,
          }]
      },
  });
</script>

Works great.

That’s the way to do it!

Thank you Ken. I appreciate all your support. I know you give a lot.

I’m not sure where you got the information about needing to load security or json_script - those instructions are not in the page I linked to.

But I’m glad you got it all working, well done!