Issue
I am currently coding a small website with Thymeleaf and Spring which should show a dynamic matrix which you can load and save. The problem with that is, though, that I can't set a definitive value with Thymeleaf since once I have th:field
in an element I can't give it a value anymore.
Now I searched a bit and found out, that you can give the filled object to the Thymeleaf component, and it will automatically insert the data. Now this somewhat works, but Thyemeleaf now puts the whole list into every single field.
This is my code:
html
<form th:object="${projectData}" method="post" class="card">
<div class="card-content">
<div class="content">
<div class="columns is-gapless is-multiline is-mobile">
<tr th:each="_, index: ${projectData.matrixData}">
<div th:if="${index.index % matrixSize == 0}" class="break column is-
desktop"></div>
<input th:field="*{matrixData}"
class="column"
type="text"
th:if="${#arrays.contains(matrixDisabledFields, index.index)}"
th:id="${index.index}"
disabled>
<input th:field="*{matrixData}"
class="column"
type="text"
th:unless="${#arrays.contains(matrixDisabledFields, index.index)}"
th:id="${index.index}">
</tr>
</div>
<input type="submit" class="button is-light is-pulled-right" value="Save">
</div>
</div>
</form>
Controller
@GetMapping("/matrix/{id}")
String getMatrix(Model model, @PathVariable Integer id) {
ProjectData projectData = JsonConverter.getProjectDataWithID(id);
if (projectData == null) {
model.addAttribute("error", "Invalid id");
return "error";
}
String[] matrix;
if (projectData.getMatrixData() == null) {
matrix =
new String[(int) Math.pow(projectData.getProjectOptions().getMatrixSize(), 2)];
} else {
matrix = projectData.getMatrixData();
}
int matrixLength = (int) Math.sqrt(matrix.length);
Integer[] matrixDisabledFieldIds = new Integer[matrixLength];
Integer pastIndex = -matrixLength - 1;
for (int i = 0; i < matrixLength; i++) {
matrixDisabledFieldIds[i] = pastIndex + matrixLength + 1;
pastIndex = matrixDisabledFieldIds[i];
matrix[pastIndex] = "X";
}
projectData = new ProjectData();
projectData.setMatrixData(matrix);
model.addAttribute("matrixSize", matrixLength);
model.addAttribute("matrixDisabledFields", matrixDisabledFieldIds);
model.addAttribute("projectData", projectData);
return "matrix";
}
And this is how it looks in the application:
And this is how it's supposed to look:
Solution
The simplest fix is probably to change both of these lines in your template from this:
th:field="*{matrixData}"
to this:
th:field="*{matrixData[__${index.index}__]}"
The __${...}__
syntax is the Thymeleaf preprocessor expression (an expression surrounded by double-underscores).
In your case, this will evaluate to each of the index values into the matrix array, so you can grab only the one relevant value you want for each cell.
It will end up looking something like this (but nicer, with your CSS styling):
Answered By - andrewJames
Answer Checked By - David Marino (JavaFixing Volunteer)