Reputation: 27
I'm working on a Spring Boot application. I have a favorite button in which the button image changes depending on if the user has Favorited the item.
Originally I had it working by accepting a form post request, updating the DB, and sending a redirect back to the Referer, but this was reloading the page every time, so I thought I would try using jQuery Ajax.
Controller.java:
// //Favorite/Unfavorite existing recipes
// @RequestMapping(value = "/recipes/{id}/favorite", method = RequestMethod.POST)
// public String favoriteRecipe(@PathVariable Long id, Model model, HttpServletRequest request, Authentication
// authentication) {
//
// User user = userService.findByUsername(authentication.getName());
// model.addAttribute("user", user);
// Recipe recipe = recipeService.findById(id);
//
// userService.toggleFavorite(user, recipe);
//
// userService.save(user);
//
// return "redirect:" + request.getHeader("Referer");
// }
// Favorite/Unfavorite existing recipes
@PostMapping("/recipes/{id}/favorite")
@ResponseStatus(value = HttpStatus.OK)
public void favoriteRecipe(@PathVariable("id") Long id, Model model, Authentication authentication) {
User user = userService.findByUsername(authentication.getName());
//model.addAttribute("user", user);
Recipe recipe = recipeService.findById(id);
userService.toggleFavorite(user, recipe);
userService.save(user);
//return new ResponseEntity<>(HttpStatus.OK);
}
index.html:
<a th:href="@{|/details/${recipe.id}|}">
<div class="grid-70">
<p>
<form id="test" th:action="@{|/recipes/${recipe.id}/favorite|}" method="post" style="display:inline">
<button type="submit" id="favorite-button-index">
<img th:src="${recipe.userFavorites.contains(#authentication.name)} ? @{/assets/images/favorited.svg} : @{/assets/images/favorite.svg}"
style="height: 12px;">
</button>
</form>
<span th:text="${recipe.name}"> </span>
</p>
</div>
</a>
app.js:
$('#test').submit(function (e) {
e.preventDefault()
$('#favorite-button-detail').submit(function (e) {
e.preventDefault()
var recipeID = [[${recipe.id}]];
var url = "/recipes/" + recipeID + "/favorite";
$.post(url, function(data) {
alert(data)
});
})
})
This is the way I tried implementing in my app.js. I have confirmed the data is being updated in the DB, but I am unable to stop the redirect to the POST url. The issue seems to be coming from the th:action in the form.
I've looked through a lot other questions/examples on this and haven't been able to figure out why it is happening. I've tried preventdefault, returning false, wrapping in a $( document ).ready().
Any help would be greatly appreciated. Thanks!
Upvotes: 2
Views: 681
Reputation: 354
In addition to Roko's answer you still have to figure out a solution to refresh your ui in order to change button image without refreshing the whole page because you are using a server-side rendering template engine. I suggest you just change the image of the button after a successful response like this:
$('#test').on("submit", function (e) {
e.preventDefault();
$.post(this.action, function(data) {
console.log(data);
var imageUrl = (data.favorited)?'/assets/images/favorited.svg':'/assets/images/favorite.svg';
$('#favorite-button-index>img').attr('src', imageUrl);
});
};
Also in this case to make data.favorited
work you should return a data about user has favorite or not from your spring controller method. Here is a sample that returns json data so you can easily use in javascript:
@PostMapping("/recipes/{id}/favorite")
@ResponseBody
public Map<String, Object> favoriteRecipe(@PathVariable("id") Long id, Authentication authentication) {
User user = userService.findByUsername(authentication.getName());
Recipe recipe = recipeService.findById(id);
userService.toggleFavorite(user, recipe);
userService.save(user);
boolean hasFavorite = recipe.userFavorites.contains(authentication.getName());
Map<String, Object> resultJson = new HashMap<>();
resultJson.put("favorited", hasFavorite);
return resultJson;
}
Upvotes: 0
Reputation: 206347
It's not good to have two nested submits. And I'm not sure what's the idea behind wrapping [[${recipe.id}]]
in double arrays...??
Try with:
$('#test').on("submit", function (e) {
e.preventDefault();
$.post(this.action, function(data) {
console.log(data);
});
});
where this.action
is the actual form's action attribute value @{|/recipes/${recipe.id}/favorite|}
And you don't need any button JS stuff any more.
Upvotes: 1