Home > Enterprise >  Spring Boot and Thymeleaf: iterating map entries in JavaScript
Spring Boot and Thymeleaf: iterating map entries in JavaScript

Time:09-22

Spring Boot Thymeleaf here. I have the following static HTML file that I've been testing with:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <script>
        window.onload = function() {

            var foodChart = new CanvasJS.Chart("foodChart", {
                animationEnabled: true,
                title: {
                    text: "Foods"
                },
                data: [{
                    type: "pie",
                    startAngle: 240,
                    yValueFormatString: "##0.00\"%\"",
                    indexLabel: "{label} {y}",
                    dataPoints: [
                        {y: 95.0, label: "Pizza"},
                        {y: 5.0, label: "French Fries"}
                    ]
                }]
            });
            foodChart.render();
        }
    </script>
</head>
<body>

<div id="foodChart" style="height: 300px; width: 100%;"></div>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>

</body>
</html>

This opens in a browser and works just great, Pie Chart and all.

But now I want to make the Pie Chart dynamic and I want the server to set the values of all the slices in the Pie Chart. So on the server-side (Java/Spring Boot), I have:

Map<String,BigDecimal> foodMap = new HashMap<>();
foodMap.put("Pizza", BigDecimal.valueOf(35.0)); // 35%
foodMap.put("French Fries", BigDecimal.valueOf(65.0)); // 65%

And I'm trying to figure out how to modify the HTML file (template) with Thymeleaf tags so that I can use this foodMap to drive the slices of the Pie Chart, dynamically. I think I need something like:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <script>
        window.onload = function() {

            var foodChart = new CanvasJS.Chart("foodChart", {
                animationEnabled: true,
                title: {
                    text: "Foods"
                },
                data: [{
                    type: "pie",
                    startAngle: 240,
                    yValueFormatString: "##0.00\"%\"",
                    indexLabel: "{label} {y}",
                    dataPoints: [

                    <th:each="key: ${foodMap}">
                        {<th:text="y: ${value}, label: ${key}" />}
                    </th>

                    ]
                }]
            });
            foodChart.render();
        }
    </script>
</head>
<body>

<div id="foodChart" style="height: 300px; width: 100%;"></div>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>

</body>
</html>

But this doesn't work, can anyone nudge me in the right direction?

CodePudding user response:

You should take advantage of Thymeleaf's JavaScript inlining for this. For example, if you do this:

<script th:inline="javascript">
  let foodMap = /*[[${foodMap}]]*/ {};
</script>

It will output:

<script>
  let foodMap = {"Pizza":35.0,"French Fries":65.0};
</script>

Once you have this data, it's pretty easy to convert it to the format you want. Putting it all together:

<script th:inline="javascript">
  window.onload = function() {
    let foodMap = /*[[${foodMap}]]*/ {};

    let dataPoints = [];
    for (food in foodMap) {
      dataPoints.push({
        'label': food,
        'y': foodMap[food]
      });
    };

    var foodChart = new CanvasJS.Chart("foodChart", {
      animationEnabled: true,
      title: {text: "Foods"},
      data: [{
        type: "pie",
        startAngle: 240,
        yValueFormatString: "##0.00\"%\"",
        indexLabel: "{label} {y}",
        dataPoints: dataPoints
      }]
    });
    
    foodChart.render();
  }
</script>
  • Related