Skip to main content
deleted 229 characters in body
Source Link
added 357 characters in body
Source Link

This is a continuation of this[this][1] question so right now I can get the data and it displays how many rounds a user has played and all their scores but as for the horizontal bar chart it only displays the bar chart in the first iteration in the thymeleaf th:each. So Wim Deblauwe[Wim Deblauwe][2] was nice enough to tell me I needed to use a javascript fetch() method and direct me to his website and a 40min lecture he gave about htmx. But that is all still beyond me.

enter image description here [![enter image description here][3]][3]

Using yourNew chart like thisand accordion:

console.log('Rounds: ' + JSON.stringify(rounds)); var acc = document.getElementsByClassName("accordion"); var i; for (i = 0; i < acc.length; i++) { acc[i].addEventListener("click", function() { this.classList.toggle("active"); var panel = this.nextElementSibling; if (panel.style.maxHeight) { panel.style.maxHeight = null; } else { panel.style.maxHeight = panel.scrollHeight + "px"; } }); } var datasets = []; var labelconst =charts []; for(var= i=0;i<roundsdocument.length;i++querySelectorAll('[data-counts]') {; var datasetcharts.forEach(chart ==> []{ for(var j=0;j<rounds[i].scores.length;j++) {  // Get the data-counts attribute value and split it into an dataset.push(rounds[i].scores[j].score)array }  const countsTest console= chart.loggetAttribute(dataset'data-counts').split(',');   const counts = {}; // Loop over each value in the array and count occurrences   for (constlet numi of= dataset0; i < countsTest.length; i++) { const num = parseInt(countsTest[i]);   counts[num] = counts[num] ? counts[num] + 1 : 1;   }     console.log(countscountsTest); // Log the countsTest array label console.pushlog("Scorecounts); Round// "Log +the counts object // Destroy any existing chart instance for the canvas element  const oldChart = chart.chart; if (i+1)oldChart) { datasets oldChart.pushdestroy(counts);   }   var newdatasets = []; // Create a new chart instance for the canvas element var keys const myChart = Object.keysnew Chart(datasets[0])chart, { for(j=0;j<keys.length;j++) { type: 'bar', newdatasets.push( options: { data responsive: []true, key maintainAspectRatio: keys[j]false, label: "Score " + keys[j] indexAxis: 'y', });  }  for(i=0;i<newdatasets.length;i++)  scales: { for(j=0;j<datasets.length;j++)  x: { console.log(datasets[j][newdatasets[i].key]);  newdatasets[i].data.push(datasets[j][newdatasets[i].key])stacked: true, }  }  console.log(newdatasets) var ctx = document.getElementById("myChart").getContext("2d"); var myChart = new Chart(ctx,display: {false type: 'bar' }, data y: { labels stacked: labeltrue, datasets display: newdatasetsfalse }   }, options plugins: { responsive legend: true,{ maintainAspectRatio display: false, indexAxis: 'y' } } }, scales data: { x labels: ["Score"], datasets: [{ stacked data: true[counts[2] || 0], display backgroundColor: false"#77ACD8"   },{ y data: [counts[3] || 0]  },{ stacked data: true[counts[4] || 0], display backgroundColor: false"#FDC26A"   },{ } data: [counts[5] || 0], plugins backgroundColor: "#FCAE37"  },{ legend data: {[counts[6] || 0, counts[7] || 0, counts[8] || 0, counts[9] || 0, counts[10] || 0], display backgroundColor: false"#FCAE37"   }]   },   });  chart.chart = myChart; }); 
<th:block th:each="round : ${roundCourse.rounds}"> ... <div class="container-fluid"> <canvas th:id="myChart"><data-counts="${round.barChartArray}" th:id="'myChart-' + ${round.roundId}"></canvas> </div> </th:block> ... <script th:inline="javascript"> let rounds = /*[[${roundsJsonNode}]]*/ {}; </script> 

So by the screen shot, all the data is there, I wasnt sure how to send the list of Thymeleaf ${round.barChartArray} to the javascript, so (as you can see aboveget a barchart in each round now, the controller I created a list of rounds and passed it directly toproblem is the js usingdata in the chart is now wrong. It's always missing by one or has one too many. The console.log shows with this score array: let[2', rounds' =4', /*[[${roundsJsonNode}]]*/' {};4', ' 2', ' 3', ' 2', ' 3', ' 3', ' 3] The problem is all barcharts are in one round now. The order is correct the data I get this

2:2, 3:4, 4:2, NaN: 1 

What is there using either model attributes, I just don't know how to put each bar chart on each round. Check the original question for complete html etc.issue here? [1]: Best practice for creating a dynamic horizontal bar chart using Spring, Thymeleaf and Javascript [2]: https://stackoverflow.com/users/40064/wim-deblauwe [3]: https://i.sstatic.net/Blf1C.png [4]: enter image description herehttps://i.sstatic.net/zQ7eT.png

This is a continuation of this question so right now I can get the data and it displays how many rounds a user has played and all their scores but as for the horizontal bar chart it only displays the bar chart in the first iteration in the thymeleaf th:each. So Wim Deblauwe was nice enough to tell me I needed to use a javascript fetch() method and direct me to his website and a 40min lecture he gave about htmx. But that is all still beyond me.

enter image description here

Using your chart like this:

console.log('Rounds: ' + JSON.stringify(rounds)); var acc = document.getElementsByClassName("accordion"); var i; for (i = 0; i < acc.length; i++) { acc[i].addEventListener("click", function() { this.classList.toggle("active"); var panel = this.nextElementSibling; if (panel.style.maxHeight) { panel.style.maxHeight = null; } else { panel.style.maxHeight = panel.scrollHeight + "px"; } }); } var datasets = []; var label = []; for(var i=0;i<rounds.length;i++) { var dataset = [] for(var j=0;j<rounds[i].scores.length;j++) {  dataset.push(rounds[i].scores[j].score) }  console.log(dataset) const counts = {}; for (const num of dataset) { counts[num] = counts[num] ? counts[num] + 1 : 1; } console.log(counts) label.push("Score Round " + (i+1)) datasets.push(counts) } var newdatasets = []; var keys = Object.keys(datasets[0]) for(j=0;j<keys.length;j++) { newdatasets.push({ data: [], key: keys[j], label: "Score " + keys[j] });  }  for(i=0;i<newdatasets.length;i++) { for(j=0;j<datasets.length;j++) { console.log(datasets[j][newdatasets[i].key]);  newdatasets[i].data.push(datasets[j][newdatasets[i].key]) }  }  console.log(newdatasets) var ctx = document.getElementById("myChart").getContext("2d"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: label, datasets: newdatasets }, options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', scales: { x: { stacked: true, display: false }, y: { stacked: true, display: false } }, plugins: { legend: { display: false } }, } }); 
<th:block th:each="round : ${roundCourse.rounds}"> ... <div class="container-fluid"> <canvas th:id="myChart"></canvas> </div> </th:block> ... <script th:inline="javascript"> let rounds = /*[[${roundsJsonNode}]]*/ {}; </script> 

So by the screen shot, all the data is there, I wasnt sure how to send the list of Thymeleaf ${round.barChartArray} to the javascript, so (as you can see above in the controller I created a list of rounds and passed it directly to the js using the let rounds = /*[[${roundsJsonNode}]]*/ {}; The problem is all barcharts are in one round now. The order is correct the data is there using either model attributes, I just don't know how to put each bar chart on each round. Check the original question for complete html etc. enter image description here

This is a continuation of [this][1] question so right now I can get the data and it displays how many rounds a user has played and all their scores but as for the horizontal bar chart it only displays the bar chart in the first iteration in the thymeleaf th:each. So [Wim Deblauwe][2] was nice enough to tell me I needed to use a javascript fetch() method and direct me to his website and a 40min lecture he gave about htmx. But that is all still beyond me.

[![enter image description here][3]][3]

New chart and accordion:

var acc = document.getElementsByClassName("accordion"); var i; for (i = 0; i < acc.length; i++) { acc[i].addEventListener("click", function() { this.classList.toggle("active"); var panel = this.nextElementSibling; if (panel.style.maxHeight) { panel.style.maxHeight = null; } else { panel.style.maxHeight = panel.scrollHeight + "px"; } }); } const charts = document.querySelectorAll('[data-counts]'); charts.forEach(chart => {  // Get the data-counts attribute value and split it into an array const countsTest = chart.getAttribute('data-counts').split(',');   const counts = {}; // Loop over each value in the array and count occurrences   for (let i = 0; i < countsTest.length; i++) { const num = parseInt(countsTest[i]);   counts[num] = counts[num] ? counts[num] + 1 : 1;   }     console.log(countsTest); // Log the countsTest array  console.log(counts); // Log the counts object // Destroy any existing chart instance for the canvas element  const oldChart = chart.chart; if (oldChart) {  oldChart.destroy();   }    // Create a new chart instance for the canvas element  const myChart = new Chart(chart, {  type: 'bar',  options: {  responsive: true,  maintainAspectRatio: false,  indexAxis: 'y',   scales: {   x: { stacked: true, display: false  },  y: {  stacked: true,  display: false }   },  plugins: {  legend: {  display: false  } } },  data: {  labels: ["Score"], datasets: [{  data: [counts[2] || 0],  backgroundColor: "#77ACD8"   },{  data: [counts[3] || 0]  },{  data: [counts[4] || 0],  backgroundColor: "#FDC26A"   },{  data: [counts[5] || 0],  backgroundColor: "#FCAE37"  },{  data: [counts[6] || 0, counts[7] || 0, counts[8] || 0, counts[9] || 0, counts[10] || 0],  backgroundColor: "#FCAE37"   }]   }   });  chart.chart = myChart; }); 
<th:block th:each="round : ${roundCourse.rounds}"> ... <div class="container-fluid"> <canvas th:data-counts="${round.barChartArray}" th:id="'myChart-' + ${round.roundId}"></canvas> </div> </th:block> ... <script th:inline="javascript"> let rounds = /*[[${roundsJsonNode}]]*/ {}; </script> 

So I can get a barchart in each round now, the problem is the data in the chart is now wrong. It's always missing by one or has one too many. The console.log shows with this score array: [2', ' 4', ' 4', ' 2', ' 3', ' 2', ' 3', ' 3', ' 3] I get this

2:2, 3:4, 4:2, NaN: 1 

What is the issue here? [1]: Best practice for creating a dynamic horizontal bar chart using Spring, Thymeleaf and Javascript [2]: https://stackoverflow.com/users/40064/wim-deblauwe [3]: https://i.sstatic.net/Blf1C.png [4]: https://i.sstatic.net/zQ7eT.png

deleted 1727 characters in body
Source Link

So Ive create (I guess) a DTO CourseByRound object that looks like this is the my js now:

console.log(rounds); var acc = document.getElementsByClassName("accordion"); for (var i = 0; i < acc.length; i++) { acc[i].addEventListener("click", function() { this.classList.toggle("active"); var panel = this.nextElementSibling; if (panel.style.maxHeight) { panel.style.maxHeight = null; } else { panel.style.maxHeight = panel.scrollHeight + "px"; } }); } var datasets = []; var label = []; for(var i=0;i<rounds.length;i++) { var dataset = [] for(var j=0;j<rounds[i].scores.length;j++) { dataset.push(rounds[i].scores[j].score) } console.log(dataset) const counts = {}; for (const num of dataset) { counts[num] = counts[num] ? counts[num] + 1 : 1; } console.log(counts) label.push("Score Round " + (i+1)) datasets.push(counts) } var newdatasets = []; var keys = Object.keys(datasets[0]) for(j=0;j<keys.length;j++) { newdatasets.push({ data: [], key: keys[j], label: "Score " + keys[j] }); } for(i=0;i<newdatasets.length;i++) { for(j=0;j<datasets.length;j++) { console.log(datasets[j][newdatasets[i].key]); newdatasets[i].data.push(datasets[j][newdatasets[i].key]) } } console.log(newdatasets) var ctx = document.getElementById("myChart").getContext("2d"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: label, datasets: newdatasets }, options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', scales: { x: { stacked: true, display: false }, y: { stacked: true, display: false } }, plugins: { legend: { display: false } }, } }); 

My Controller

@GetMapping("/rounds/{id}") public String roundsHome(@PathVariable(value = "id") Long id, Model model) { List<Course> courses = courseService.getAllCourses(); List<Round> rounds = userService.getUserById(id).getRounds(); rounds.sort(Comparator.comparing(Round::getRoundDate).reversed()); Map<Course, List<Round>> mapRoundsByCourse = rounds.stream().collect(Collectors.groupingBy(Round::getCourse)); try { ObjectMapper mapper = new ObjectMapper(); JsonNode json = mapper.readTree(mapper.writeValueAsString(mapRoundsByCourse)); model.addAttribute("roundsJson", json); } catch (IOException e) { e.printStackTrace(); } model.addAttribute("userId", id); model.addAttribute("roundService", roundService); model.addAttribute("courses", courses); model.addAttribute("rounds", mapRoundsByCourse); return "/discgolf/round/rounds"; } 

And updated script

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

The 'let rounds' is null? Screen shot, line 27 is for(var i=0;i<rounds.length;i++) { enter image description here

Models Course

@Entity @Table(name = "course") @Builder public class Course { @Id @Column(name = "course_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;  @Column(nullable = false)courseId; private String name;  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "course_id", referencedColumnName = "course_id")courseName; private List<Hole> holes = new ArrayList<>(); @Column(name = "course_par", nullable =int false)coursePar; private int par; courseRecord; @Column(name = "record", nullableprivate =double false)courseAverage; private int record; timesPlayed;  @Column(name = "course_average", nullable = false) private doubleList<Round> courseAverage;rounds;  //Constructorconstructor, getters and setters. } 

HoleUsing your chart like this:

@Entityconsole.log('Rounds: ' + JSON.stringify(rounds)); @Table var acc = document.getElementsByClassName(name"accordion"); var i; for (i = "hole"0; i < acc.length; i++) { public class Hole  acc[i].addEventListener("click", function() {  this.classList.toggle("active"); @Id var panel = this.nextElementSibling; @Column if (namepanel.style.maxHeight) { panel.style.maxHeight = "hole_id"null; } else { panel.style.maxHeight = panel.scrollHeight + "px"; } }); @GeneratedValue} var datasets = []; var label = []; for(strategyvar i=0;i<rounds.length;i++) {  var dataset = GenerationType[] for(var j=0;j<rounds[i].IDENTITYscores.length;j++) { private Long holeId; dataset.push(rounds[i].scores[j].score)  } @Column console.log(namedataset)  const counts = "name"{}; for (const num of dataset) { private int number; counts[num] = counts[num] ? counts[num] + 1 : 1; }  console.log(counts) @Column label.push(name"Score Round " + (i+1)) datasets.push(counts)  } var newdatasets = "par"[]; var keys = Object.keys(datasets[0])  for(j=0;j<keys.length;j++) {  private int par;newdatasets.push({ //Constructor data: [],   getters and setters key: keys[j], label: "Score " + keys[j] }); } for(i=0;i<newdatasets.length;i++) { for(j=0;j<datasets.length;j++) { console.log(datasets[j][newdatasets[i].key]); newdatasets[i].data.push(datasets[j][newdatasets[i].key]) } } console.log(newdatasets) var ctx = document.getElementById("myChart").getContext("2d"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: label, datasets: newdatasets }, options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', scales: { x: { stacked: true, display: false }, y: { stacked: true, display: false } }, plugins: { legend: { display: false } }, } }); 

ScoreMy html

@Entity @Table(name = "score") public<th:block classth:each="round Score: ${ @Id @Column(name = "score_id")roundCourse.rounds}">  @GeneratedValue(strategy = GenerationType.IDENTITY)..  private Long<div scoreId; class="container-fluid">   @Column(name =<canvas "score")th:id="myChart"></canvas>  private int score;</div> </th:block>  @Column(name = "hole_par")...  private int<script holePar; th:inline="javascript"> private String name; let privaterounds String= color; /*[[${roundsJsonNode}]]*/Constructor, getters and setters.{}; </script> 

RoundInside the controller getCourseByRound(id) just gets a list of CourseByRound by a userId

@Entity @Table(nameList<CourseByRound> courseByRounds = "round"getCourseByRound(id); public class Round {  @Id  List<Round> @Column(namejsonRounds = "round_id") new @GeneratedValueArrayList<>(strategy = GenerationType.IDENTITY); private Long roundId;  for @JsonIgnore (CourseByRound courseByRound : courseByRounds) @ManyToOne{ @JoinColumn(name = "course_id")  private Course course; for @OneToMany(cascade = CascadeType.ALL,Round orphanRemovalround =: truecourseByRound.getRounds()) { @JoinColumn(name = "round_id", referencedColumnName = "round_id")  private List<Score> scores = new ArrayList<>jsonRounds.add(round);   @JsonDeserialize(using = LocalDateTimeDeserializer.class)  @Column(name = "round_date")} @DateTimeFormat(pattern = "dd/MM/yyyy")  private Date roundDate;} rounds.sort(Comparator.comparing(Round::getRoundDate).reversed()); ObjectMapper mapper = new @ColumnObjectMapper(name = "round_total");  private intmapper.registerModule(new total;JavaTimeModule()); //Constructormodel.addAttribute("roundsJsonNode", getters and settersjsonRounds); model.addAttribute("courseByRounds", courseByRounds); 

Json DataSo by the screen shot, all the data is there, I wasnt sure how to send the list of Thymeleaf ${round.barChartArray} to the javascript, so (as you can see above in the controller I created a list of rounds and passed it directly to the js using the let rounds = /*[[${roundsJsonNode}]]*/ {}; The problem is all barcharts are in one round now. The order is correct the data is there using either model attributes, I just don't know how to put each bar chart on each round. Check the original question for complete html etc. enter image description hereenter image description here

So this is the my js now:

console.log(rounds); var acc = document.getElementsByClassName("accordion"); for (var i = 0; i < acc.length; i++) { acc[i].addEventListener("click", function() { this.classList.toggle("active"); var panel = this.nextElementSibling; if (panel.style.maxHeight) { panel.style.maxHeight = null; } else { panel.style.maxHeight = panel.scrollHeight + "px"; } }); } var datasets = []; var label = []; for(var i=0;i<rounds.length;i++) { var dataset = [] for(var j=0;j<rounds[i].scores.length;j++) { dataset.push(rounds[i].scores[j].score) } console.log(dataset) const counts = {}; for (const num of dataset) { counts[num] = counts[num] ? counts[num] + 1 : 1; } console.log(counts) label.push("Score Round " + (i+1)) datasets.push(counts) } var newdatasets = []; var keys = Object.keys(datasets[0]) for(j=0;j<keys.length;j++) { newdatasets.push({ data: [], key: keys[j], label: "Score " + keys[j] }); } for(i=0;i<newdatasets.length;i++) { for(j=0;j<datasets.length;j++) { console.log(datasets[j][newdatasets[i].key]); newdatasets[i].data.push(datasets[j][newdatasets[i].key]) } } console.log(newdatasets) var ctx = document.getElementById("myChart").getContext("2d"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: label, datasets: newdatasets }, options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', scales: { x: { stacked: true, display: false }, y: { stacked: true, display: false } }, plugins: { legend: { display: false } }, } }); 

My Controller

@GetMapping("/rounds/{id}") public String roundsHome(@PathVariable(value = "id") Long id, Model model) { List<Course> courses = courseService.getAllCourses(); List<Round> rounds = userService.getUserById(id).getRounds(); rounds.sort(Comparator.comparing(Round::getRoundDate).reversed()); Map<Course, List<Round>> mapRoundsByCourse = rounds.stream().collect(Collectors.groupingBy(Round::getCourse)); try { ObjectMapper mapper = new ObjectMapper(); JsonNode json = mapper.readTree(mapper.writeValueAsString(mapRoundsByCourse)); model.addAttribute("roundsJson", json); } catch (IOException e) { e.printStackTrace(); } model.addAttribute("userId", id); model.addAttribute("roundService", roundService); model.addAttribute("courses", courses); model.addAttribute("rounds", mapRoundsByCourse); return "/discgolf/round/rounds"; } 

And updated script

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

The 'let rounds' is null? Screen shot, line 27 is for(var i=0;i<rounds.length;i++) { enter image description here

Models Course

@Entity @Table(name = "course") @Builder public class Course { @Id @Column(name = "course_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;  @Column(nullable = false) private String name;  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "course_id", referencedColumnName = "course_id") private List<Hole> holes = new ArrayList<>(); @Column(name = "course_par", nullable = false) private int par;  @Column(name = "record", nullable = false) private int record;   @Column(name = "course_average", nullable = false) private double courseAverage; //Constructor, getters and setters. 

Hole

@Entity @Table(name = "hole") public class Hole { @Id @Column(name = "hole_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long holeId; @Column(name = "name") private int number; @Column(name = "par") private int par; //Constructor, getters and setters. 

Score

@Entity @Table(name = "score") public class Score { @Id @Column(name = "score_id")  @GeneratedValue(strategy = GenerationType.IDENTITY)  private Long scoreId;    @Column(name = "score")  private int score;  @Column(name = "hole_par")  private int holePar;  private String name;  private String color; //Constructor, getters and setters. 

Round

@Entity @Table(name = "round") public class Round {  @Id  @Column(name = "round_id")  @GeneratedValue(strategy = GenerationType.IDENTITY) private Long roundId;  @JsonIgnore  @ManyToOne @JoinColumn(name = "course_id")  private Course course;  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "round_id", referencedColumnName = "round_id")  private List<Score> scores = new ArrayList<>();   @JsonDeserialize(using = LocalDateTimeDeserializer.class)  @Column(name = "round_date") @DateTimeFormat(pattern = "dd/MM/yyyy")  private Date roundDate; @Column(name = "round_total")  private int total; //Constructor, getters and setters. 

Json Data enter image description here

So Ive create (I guess) a DTO CourseByRound object that looks like this:

private Long courseId; private String courseName; private int coursePar; private int courseRecord; private double courseAverage; private int timesPlayed; private List<Round> rounds;  //constructor, getters and setters } 

Using your chart like this:

console.log('Rounds: ' + JSON.stringify(rounds));  var acc = document.getElementsByClassName("accordion"); var i; for (i = 0; i < acc.length; i++) {   acc[i].addEventListener("click", function() {  this.classList.toggle("active");  var panel = this.nextElementSibling;  if (panel.style.maxHeight) { panel.style.maxHeight = null; } else { panel.style.maxHeight = panel.scrollHeight + "px"; } }); } var datasets = []; var label = []; for(var i=0;i<rounds.length;i++) {  var dataset = [] for(var j=0;j<rounds[i].scores.length;j++) {  dataset.push(rounds[i].scores[j].score)  }  console.log(dataset)  const counts = {}; for (const num of dataset) {  counts[num] = counts[num] ? counts[num] + 1 : 1; }  console.log(counts)  label.push("Score Round " + (i+1)) datasets.push(counts)  } var newdatasets = []; var keys = Object.keys(datasets[0])  for(j=0;j<keys.length;j++) {  newdatasets.push({  data: [],    key: keys[j], label: "Score " + keys[j] }); } for(i=0;i<newdatasets.length;i++) { for(j=0;j<datasets.length;j++) { console.log(datasets[j][newdatasets[i].key]); newdatasets[i].data.push(datasets[j][newdatasets[i].key]) } } console.log(newdatasets) var ctx = document.getElementById("myChart").getContext("2d"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: label, datasets: newdatasets }, options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', scales: { x: { stacked: true, display: false }, y: { stacked: true, display: false } }, plugins: { legend: { display: false } }, } }); 

My html

<th:block th:each="round : ${roundCourse.rounds}"> ... <div class="container-fluid"> <canvas th:id="myChart"></canvas> </div> </th:block> ... <script th:inline="javascript"> let rounds = /*[[${roundsJsonNode}]]*/ {}; </script> 

Inside the controller getCourseByRound(id) just gets a list of CourseByRound by a userId

List<CourseByRound> courseByRounds = getCourseByRound(id); List<Round> jsonRounds = new ArrayList<>(); for (CourseByRound courseByRound : courseByRounds) { for (Round round : courseByRound.getRounds()) { jsonRounds.add(round); } } rounds.sort(Comparator.comparing(Round::getRoundDate).reversed()); ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); model.addAttribute("roundsJsonNode", jsonRounds); model.addAttribute("courseByRounds", courseByRounds); 

So by the screen shot, all the data is there, I wasnt sure how to send the list of Thymeleaf ${round.barChartArray} to the javascript, so (as you can see above in the controller I created a list of rounds and passed it directly to the js using the let rounds = /*[[${roundsJsonNode}]]*/ {}; The problem is all barcharts are in one round now. The order is correct the data is there using either model attributes, I just don't know how to put each bar chart on each round. Check the original question for complete html etc. enter image description here

added 96 characters in body
Source Link
Loading
added 1070 characters in body
Source Link
Loading
added 2265 characters in body
Source Link
Loading
added 87 characters in body
Source Link
Loading
added 4231 characters in body
Source Link
Loading
Source Link
Loading