I want to implement the suppression of several objectfs, and handle in my controller the different errors that might happen. I call the controller with ajax, and want to load up a fragment in my html that will indicates what happened.
I don't understand what makes ajax get my thymeleaf fragment when he receives a string in response.
Controller :
@PostMapping("/deleteMultipleMyObjects")
@ResponseBody
public ResponseEntity<Object> deleteMultipleMyObjects(Model model, @ModelAttribute("myObjectIds") String myObjectIds) {
if (myObjectIds.length() == 0) {
MessageHelper.addInfoAttribute(model, "objects.delete.none");
return ResponseEntity.badRequest().body("fragments/components :: ajaxResponse");
}
// The service brings back two lists : the ids deleted and those non-deleted (for any reason)
Pair<List<Long>, List<Long>> res = myObjectService.deleteMultipleMyObjects(myObjectIds);
if (!res.getValue1().isEmpty()) {
// Here I want to send back a warning, and handle the objects I did not delete
MessageHelper.addWarningAttribute(model, "objects.delete.warn", res.getValue1());
return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED).body(new Pair<>(res.getValue0(), "fragments/components :: ajaxResponse"));
}
// If all goes well, success
MessageHelper.addSuccessAttribute(model, "objects.delete.ok");
return ResponseEntity.accepted().body("fragments/components :: ajaxResponse");
}
The fragment I want to get (and that is used many times in my code) - components.html :
<div id="ajaxResponse" th:fragment="ajaxResponse (type, message)" class="alert alert-dismissable" th:classappend="'alert-' + ${message.type.name().toLowerCase()}">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<span th:if="${message.args==null or message.args.length==0}" th:text="#{${message.message}}">An error happened</span>
<span th:if="${message.args!=null and message.args.length==1}" th:text="#{${message.message}(${message.args[0]})}">An error happened</span>
</div>
The html where I visualize and handle my objects - objects.html :
<div id="alertDiv">
</div>
<div id="deleteMultipleMyObjects" class="btn" onclick="deleteMultipleMyObjects()">Delete multiple objects</div>
<table>
<!-- a table containing my objects and with a checkbox to select those who will be deleted-->
</table>
And finally my javascript - objects.js
:
function deleteMultipleMyObjects() {
let myObjectIds = getAllCheckedObjects(); // sends back a string with the ids of the checked objects : "id1,id3,id6"
let fragment;
$.post("deleteMultipleMyObjects", {myObjectIds: myObjectIds})
.done(function (data, status, xhr){
hideAllCheckedObjects();
fragment = data; // !!! Here I get the name of the fragment instead of the html
})
.fail(function(xhr, status, error){
if (undefined != xhr.responseJSON && xhr.responseJSON.value0.length > 0) {
hideLinesWithId(xhr.responseJSON.value0);
fragment = xhr.responseJSON.value1; // !!! Here I get the name of the fragment instead of the html
} else {
fragment = xhr.responseText; // !!! Here I get the name of the fragment instead of the html
}
})
.always(function(xhr, status, error) {
$("#alertDiv").text("");
$("#alertDiv").append(fragment); // !!! Here I'd like my alertDiv to receive the full html of my fragment
});
}
Each time I get an xhr or data containing literally the name of the fragment ("fragments/components :: ajaxResponse") instead of the html of it.
I got other places in my code where I use $.ajax or $.post and I get back the html of the fragment but at those places my Controller sends back a String and not a ResponseEntity. Here I'd really like to have my http response code to handle the different responses and also a body with data and also my fragment. It seems I can't have them all...
When you use @RestController
or @ResponseBody
you are saying that you want to return data rather than render an MVC view. Similarly, I don't think you can use ResponseEntity
if you want to render a view, just return the view name String
or a ModelAndView
.