3
votes

Using Asp.Net MVC, I am trying to create a web page that displays multiple bar charts on a single page using the chart.js library. Each chart has different data and is created in its own partial view. Instead of creating multiple different charts though, the last chart data is overwriting the first chart on the page, and all the remaining charts appear blank. As you can see in the picture below, the "Title and Segments" data and legend overwrote the "Producers" data, and the "Title and Segments" chart is empty.

enter image description here

On the main view page, I use a foreach loop to render the same partial view for each report.

@foreach (Report report in Model.Reports)
{
    @Html.Partial("BarChartPartialView", report);
}

In my partial view, I create a dynamic ID name for the canvas object based on a value in the Model. This was an attempt to overcome the issue mentioned in Chart.js - Multiple Line Charts - Only Show Last Chart.

@{
    string name = "canvas" + Model.CurrentReport.ID;
}

I then create a canvas object using the dynamic ID.

<canvas id="@name"></canvas>

In the chart.js script that is also in my partial view, I used eval() to create dynamic ctx and myBar variables. (Source of idea: How do i declare and use dynamic variables in javascript?)

<script>
    var barChartData = {
        labels: [@Html.Raw(Model.Labels)],
        datasets: [@Html.Raw(Model.Data)]
    };

    $(document).ready(function () {      
        eval("var ctx" + "@name" + "=document.getElementById('@name').getContext('2d');");

        var temp = new Chart(eval('ctx' + '@name'), {
            type: 'bar',
            data: barChartData,
            options: {
                elements: {
                    rectangle: {
                        borderWidth: 2,
                        borderColor: 'rgb(0, 255, 0)'
                    }
                },
                legend: {
                    position: 'bottom'
                },
                title: {
                    display: true,
                    text: '@Model.CurrentReport.Name'
                }
            }
        });

        eval('window.myBar' + '@name' + "= temp;");
    });
</script>

I've seen other similar questions, yet none seemed to have a solution for my problem:
multiple chartjs in the same page
Rendering HTML5 Charts in partial views show only blank data

1
Are you using eval to make the ctx variables names different? I think you solved that problem with the document ready function.Alexander Lindsay
@AlexanderLindsay That was my goal, but it didn't change anything. I get the same messed up results if I use just ctx for all the charts, or if I use eval() like my current attempt.Tot Zam

1 Answers

2
votes

I think the problem is that the barChartData gets overwritten by each of the partial views. Try putting that variable inside the document ready function.

Alternatively, use a self executing function to do all the chart stuff.

(function(){
    var data = {};
})();

Basically, the issue is that each of the partial views is adding a copy of barChartData to the page. Each of which is defined in the window scope. So the page is going to look something like this:

<script>
    var barChartData = {
        labels: ModelOneLabels,
        datasets: ModelOneData
    };
    ...
</script>

<script>
    var barChartData = {
        labels: ModelTwoLabels,
        datasets: ModelTwoData
    };
    ...
</script>

That will leave barChartData with the model two values.

You should be able to look at the generated page and see the multiple script tags. The console in your browsers developer tools should verify as well.

Here is how you can fix it:

<script>
    $(document).ready(function () {
        var barChartData = {
            labels: [@Html.Raw(Model.Labels)],
            datasets: [@Html.Raw(Model.Data)]
        };

        var ctx = document.getElementById('@name').getContext('2d');

        // I am not sure how you are using the window.myBar@name var
        // if you are referencing it later than you may need to adjust this part
        var myBar = new Chart(ctx, {
          type: 'bar',
          data: barChartData,
          options: {
              elements: {
                  rectangle: {
                      borderWidth: 2,
                      borderColor: 'rgb(0, 255, 0)',
                      borderSkipped: 'bottom'
                  }
              },
              legend: { 
                  position: 'bottom' 
              }, 
              title: {
                  display: true, 
                  text: '@Model.CurrentReport.Name'
              }
        })

});
</script>