I have a Controller like this:
@Controller
public class DeviceController {
@Inject
private DeviceService deviceService;
@ModelAttribute("devices")
public List<Device> getDevices() {
return deviceService.getAll();
}
@GetMapping({"/", "index.html"})
public String showIndex() {
return "index";
}
@DeleteMapping(value = "/devices/{id}")
public String deleteOne(@PathVariable("id") long id) {
deviceService.deleteOne(id);
return "index :: devices";
}
}
And a Thymeleaf template like this:
<table id="tbl_device" th:fragment="devices">
<tr> <!-- header --> </tr>
<tr th:each="e : ${devices}" th:object="${d}" th:id="'device_' + *{id}" th:fragment="'device_' + *{id}">
<!-- columns -->
</tr>
</table>
When I call the /devices/{id}
DELETE endpoint, I would expect it to return the table without the deleted device. But it actually returns the table including the deleted device. When I debug the code, I can see that getDevices()
is called before deleteOne(id)
.
When I manually reload the page after deleting, the row is (correctly) not displayed anymore.
Why is that? And (how) can I change this behaviour?
Thanks
Why is that?
I recommend to read this article. According to that:
In general, Spring-MVC will always make a call first to that method, before it calls any request handler methods. That is, @ModelAttribute methods are invoked before the controller methods annotated with @RequestMapping are invoked. The logic behind the sequence is that, the model object has to be created before any processing starts inside the controller methods.
I doubt you can alter invocation order, but what you can do is additionally pass model attribute to your deleteOne
method and modify it there.
@DeleteMapping(value = "/devices/{id}")
public String deleteOne(@PathVariable("id") long id, @ModelAttribute("devices") List<Device> devices) {
deviceService.deleteOne(id);
devices.remove( /* just deleted device */);
return "index :: devices";
}