I am in a Java 1.8 project with Spring Boot, I have set up html page management with thymeleaf, and while the communication from Backend to Frontend works correctly, I am unable to pass data from Frontend to Backend.
I have tried to make everything extremely modular, and perhaps that is why the common solutions I find online do not fit properly.
The flow starts with a button that invokes this endpoint:
@RequestMapping(value = {"/console"}, method = RequestMethod.GET)
public String getConsole(Model model, HttpSession session) {
List<Report> reports = new ArrayList<>();
Report report1 = new Report();
report1.setTitle("Report 1");
report1.setReferenceDates(convertConsoleDate(Arrays.asList("None",
"09SEP2023", "20OCT2023", "30NOV2023", "11DEC2023", "25DEC2024"
)));
report1.setCountries(Arrays.asList("AR", "AT", "AU", "BE", "BR", "CA", "CH",
"CN", "DE", "DK", "ES", "FI", "FR", "GB", "GR", "HK", "IE", "IN", "IT",
"JP", "KR", "MX", "NL", "NO", "NZ", "PL", "PT", "RU", "SE", "SG", "US", "ZA"));
report1.setInputTypes(Arrays.asList("ONE", "TWO"));
Report report2 = new Report();
report2.setTitle("Report 2");
report2.setReferenceDates(convertConsoleDate(Arrays.asList("None",
"01JAN2022", "15FEB2022", "28MAR2022", "07APR2022", "12MAY2022",
"23JUN2022", "04JUL2022", "16AUG2022", "27SEP2022", "08OCT2022",
"19NOV2022", "31DEC2022", "11JAN2023", "22FEB2023", "05MAR2023",
"16APR2023", "27MAY2023", "07JUN2023", "18JUL2023", "29AUG2023",
"09SEP2023", "20OCT2023", "30NOV2023", "11DEC2023", "25DEC2024"
)));
report2.setCountries(Arrays.asList("AR", "ZA"));
report2.setInputTypes(Arrays.asList("FOUR"));
Report report3 = new Report();
report3.setTitle("Report 3");
report3.setCountries(Arrays.asList("ZA"));
report3.setInputTypes(Arrays.asList("FIVE"));
reports.add(report1);
reports.add(report2);
reports.add(report3);
List<String> reportTypes = reports.stream()
.map(Report::getTitle)
.collect(Collectors.toList());
Console console = new Console();
console.setReports(reports);
console.setReportTypes(reportTypes);
console.setUploadTypes(Arrays.asList("Upload 1", "Upload 2", "Upload 3"));
ReportResponse reportResponse = new ReportResponse();
session.setAttribute("reports", reports);
model.addAttribute("console", console);
model.addAttribute("reportResponse", reportResponse);
return "console";
}
which passes the data to the console.html page :
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Console</title>
<..here are bootstrap 5.3 and the style sheet..>
</head>
<body>
<container>
<div class="row">
<div class="col-4">
<div th:include="uploadPage"></div>
</div>
<div class="col-8">
<div th:include="reportPage"></div>
</div>
</div>
</container>
</body>
</html>
then reportPage.html included with thymeleaf:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Report Form</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<..here are bootstrap 5.3 and the style sheet..>
</head>
<body>
<div class="card card-width" style="height: 600px;">
<div class="card-header">
Generate reports
</div>
<div class="card-body">
<select class="form-select" id="reportType">
<option disabled selected>Choose report</option>
<option th:each="reportType : ${console?.reportTypes}" th:text="${reportType}"
th:value="${reportType}"></option>
</select>
<div class="card text-center" id="reportCard" style="margin-top:20px; height: 300px;">
<div class="card-body">
<form id="reportForm" method="post" th:action="@{/sendReport}" th:object="${reportResponse}">
<div class="row justify-content-center" id="formContent">
<div class="col-md-auto mx-3" th:if="${selectedReport?.referenceDates != null}" th:include="Report_ReferenceDate"></div>
</div><br/>
<input class="btn" id="submitBtn" style="width:300px; display:none; margin-top:50px;"
type="submit" value="Generate"/>
</form>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$("#reportType").change(function(){
var selectedReportType = $(this).children("option:selected").val();
$.ajax({
url: '/getReport',
type: 'get',
data: {reportType: selectedReportType},
success: function(response) {
var $response = $('<div>').html(response);
var formContent = $response.find('#formContent').html();
$('#formContent').html(formContent);
$("#submitBtn").show();
}
});
});
});
</script>
</body>
</html>
Which contains a form with within it an input field included with thymeleaf:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<..here are bootstrap 5.3 and the style sheet..>
</head>
<body>
<div class="dropdown d-inline-block">
<button aria-expanded="false" class="btn dropdown-toggle"
data-bs-auto-close="outside"
data-bs-toggle="dropdown" id="dropdownMenuButton" type="button"
data-selected="false">
Reference date
</button>
<div aria-labelledby="dropdownMenuButton" class="dropdown-menu" id="referenceDate"
style="max-height: 200px; overflow-y: auto;">
<input id="myInput1"
placeholder="Filter.."
style="width: 100%; padding: 10px;" type="text">
<input class="dropdown-item" th:each="date : ${selectedReport.referenceDates}" th:value="${date}" th:field="*{referenceDate}" readonly>
</div>
</div>
<script>
document.getElementById('myInput1').addEventListener('keyup', function() {
event.preventDefault();
var filter = this.value.toUpperCase();
var dropdownItems = document.querySelectorAll('.dropdown-item');
for (var i = 0; i < dropdownItems.length; i++) {
var txtValue = dropdownItems[i].value;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
dropdownItems[i].style.display = "";
} else {
dropdownItems[i].style.display = "none";
}
}
});
</script>
</body>
</html>
With ReportResponse class:
@Component
@Data
public class ReportResponse {
private String referenceDate;
}
And the endpoint to which the form points (which at this time only prints inputs):
@RequestMapping(value = "/sendReport", method = RequestMethod.POST)
public String sendReport(@ModelAttribute(value="reportResponse") ReportResponse reportResponse) {
log.info("ReportResponse: " + reportResponse);
return "console";
}
I tried different combinations:
- Inserting
th:field=“*{referenceDate}”
as it is written now, produces a compilation error:
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/modularPage.html]")
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "Report_ReferenceDate" - line 60, col 107)
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'reportResponse' available as request attribute
-
Inserting instead
field="*{referenceDate}" name="referenceDate"
(as I read in another question here on StackOverflow), so in this case the form is generated and once filled out (only one field can be selected) this is the log:
ReportResponse: ReportResponse(referenceDate=None,25DEC2024,11DEC2023,30NOV2023,20OCT2023,09SEP2023)
So it actually works, but it returns all the data. -
I was trying by inserting the th:each in the dropdown-menu and then creating a hidden input in which to dynamically enhance via javascript its value with the one currently clicked.
But I got lost in the integration with thymeleaf..
Where am I going wrong?
Can you possibly explain how to implement the solution with the hidden input?
PS: please, consider that I always selected “Report 1”
Thank you very much
user25205668 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.