I am having a hardtime to bind a ObjectList in Thymeleaf POST.
I am trying to achieve the below requirements using Spring 5 and ThymeLeaf
1. User uploads a Excel File
2. Display data in HTML Table (For Java Script Data Validation)
3. Allow User to Delete Invalid Rows (from Inmemory User Specific ArrayList)
4. Display Remaining Values
5. POST valid remaining values to Server
I am planning to add a delete button in each row, . And a Submit button to save all the remaining rows in DB.
How can I forward eachRowList to another controller (for delete action and DB save).
@PostMapping("/load-excel")
public ModelAndView loadFile(@RequestParam("fileName") MultipartFile file,
@RequestParam("selectedApplicationName") String selectedApplicationName,RedirectAttributes redirectAttr,Model model) {
List<EachRowinExcel> eachRowList = fileReaderService.convertExceltoObjList();
....
modelAndView.addObject("eachRowList", eachRowList);
return modelAndView;
}
<tr th:each="eachRow : ${eachRowList}">
<td th:text="${eachRow.column1}"></td>
<td th:text="${eachRow.column2}"></td>
<td th:text="${eachRow.column3}"></td>
<td th:text="${eachRow.column4}"></td>
<td th:text="${eachRow.column5}"></td>
<td th:text="${eachRow.column6}"></td>
<td th:text="${eachRow.column7}"></td>
<!-- Special Columns -->
<th:block th:each="customColumnValue:${eachRow.customColumnsList}">
<td th:text="${customColumnValue}"></td>
</th:block>
</tr>
Update 1:
Modified View
<form action="#" th:action="@{/access/delete}" th:object="${form}" method="post">
<table id="accessRequestDataTable" class="display compact" style="width:100%">
<thead>
<tr>
<!-- Headers -->
</tr>
</thead>
<tbody>
<tr th:each="eachRow, iter : ${form.eachRowList}">
<td th:text="${eachRow.accessReqeustCounter}" th:field="*{eachRowList[__${iter.index}__].accessReqeustCounter}"></td>
<td th:text="${eachRow.accessReqeustID}" th:field="*{eachRowList[__${iter.index}__].accessReqeustID}"></td>
<td th:text="${eachRow.accessRequestType}" th:field="*{eachRowList[__${iter.index}__].accessRequestType}"></td>
<td th:text="${eachRow.userProfile}" th:field="*{eachRowList[__${iter.index}__].userProfile}"></td>
<td th:text="${eachRow.userFinalName}" th:field="*{eachRowList[__${iter.index}__].userFinalName}"></td>
<td th:text="${eachRow.userLoginName}" th:field="*{eachRowList[__${iter.index}__].userLoginName}"></td>
<td th:text="${eachRow.userEmail}" th:field="*{eachRowList[__${iter.index}__].userEmail}"></td>
<td>
<button class="btn btn-danger btn-sm"
type="submit" value="submit">Delete</button>
</td>
</tr>
</tbody>
</table>
</form>
POST Controller
@RequestMapping(value = "/access/delete", method = RequestMethod.POST)
public ModelAndView deleteUserFromTable(@ModelAttribute("form") EachRowListWrapper eachRowListWrapper){
System.out.println(eachRowListWrapper.getEachRowList().size());
ModelAndView modelAndView = new ModelAndView();
eachRowListWrapper.getEachRowList().remove(0);
modelAndView.setViewName("access-table");
return modelAndView;
}
Update 2
Followed the similar approach for column headers. I have another List object in the wrapper class. It works at initial load, but headers are missing after returning from a POST controller.
<thead>
<tr>
<th scope="col">User Name</th>
<th scope="col">Login</th>
<th scope="col">Email</th>
<th:block th:each="key, iter : ${form.customColumns}">
<th th:text="${key}" scope="col"></th>
<input type="hidden" th:field="${form.customColumns[__${iter.index}__]}" />
</th:block>
<th scope="col">Action</th>
</tr>
</thead>
Final Update:
Apparently th:field input tag will not bind within thead section (its not supposed to have input fields LoL) . Everything works as expected after I moved it before the table starts.