I have Spring 4 MVC form with 2 submit buttons. I want these buttons to point to two different controllers. The problem is that one form should have fixed action parameter set.
This is my form:
<form:form method="post" action="pageAction" commandName="id">
<button type="submit" class="btn btn-primary" name="addBasket">
Add Basket
</button>
<button type="submit" class="btn btn-danger" name="addProduct">
Add Product
</button>
</form:form>
Is it possible that these button will reach two different controllers? I am going to send only ID, in addBasket it would be basketId, in addProduct it would be productId. These are the controllers:
#Controller
public class BasketController {
#RequestMapping(value = "/addBasket", method = RequestMethod.POST)
public ModelAndView addBasket(#ModelAttribute("id") Integer id) {
//method - addBasket(id);
}
}
#Controller
public class ProductController {
#RequestMapping(value = "/addProduct", method = RequestMethod.POST)
public ModelAndView addProduct(#ModelAttribute("id") Integer id) {
//method - addProduct(id);
}
}
If you are using html 5 and compatible browsers, you can use form and formaction attributes of buttons to target according to your needs. See details at w3schools
I am not sure if there is a solution you want, but an alternative might be to use an if statement in /addItem checking the value of name:
#Controller
public class ItemController {
#RequestMapping(value = "/addItem", method = RequestMethod.POST)
public ModelAndView addItem(#ModelAttribute("id") Integer id, #ModelAttribute("name") String name) {
if ("basket" == name) {
basketController.addBasket(id);
} else {
productController.addProduct(id);
}
}
}
You can add an onclick event on the submit button, which would call the a javascript function wherein you could decide/change the url as per the requirement.
<button type="submit" class="btn btn-primary" name="addBasket" onClick="javascript:addBasket()">
<button type="submit" class="btn btn-primary" name="addProduct" onclick="javascript:addProduct()">
Add any number of javascript functions like:
function addBasket() {
var requestURL = '/addBasket';
var formData = $("#formName").serialize();
$.ajax({
type: 'POST',
data: formData,
url: requestURL,
success: function (data1) {
//do what is required after success
},
error: function (xhr) {
//in case of failure
}
});
}
Related
I have a controller with request mapping and view where located two buttons "save" and "delete", but they don't do anything. I tried to debug it< but nothing
I used a Spring mvc with thymleaf, I tried a lot of variants, for example : action, individual controller for it, but nothing
<h:form method="post" data-th-action="#{/admin/edit-page/edit}"
th:object="${product}">
<button type="submit" name="action"
value="save">save</button>
<button type="submit" name="action"
value="cancel">cancel</button>
</h:form>
#RequestMapping(value="/admin/edit-page/edit", method=RequestMethod.POST, params="action=save")
public ModelAndView save() {
return null;
}
#RequestMapping(value="/admin/edit-page/edit", method=RequestMethod.POST, params="action=cancel")
public ModelAndView cancel() {
return null;
}
I want to perform an action based on what button was pressed
In the controller methods, your model parameter is missing.
try like bellow
#RequestMapping(value="/admin/edit-page/edit", method=RequestMethod.POST, params="action=save")
public ModelAndView save(#ModelAttribute Product product) {
//assuming Product is your class
return null;
}
// same for delete
Hello guys i have a question regarding what is mentioned in the title. Is it possible to stay on the same page and submit . I found something with javascript but it is not working for me because i m using thymleaf and spring boot. Or i just don't know how to adapt it to my case.
thymeleaf code:
<form th:action="#{/tweets/tweet}" th:object="${tweet}" method="post">
<div class="row">
<div class="col">
<input type="text" th:field="*{content}" class="form-control" placeholder="What's happening? Tell us!">
</div>
<div class="col">
<input class="form-control" type="submit" value="Submit" />
</div>
</div>
</form>
the controller class:
#Controller
#RequestMapping("tweets")
#Slf4j
public class TweetController {
private TweetService tweetService;
public TweetController(TweetService tweetService) {
this.tweetService = tweetService;
}
#PostMapping("/tweet")
#ResponseStatus(CREATED)
public Tweet tweet(#Valid #ModelAttribute("tweet") Tweet tweet, Principal
principal, BindingResult result) {
if(result.hasErrors()){
//do somethign
}
if (!tweet.getContent().equals(null) && !tweet.getContent().equals("") && !tweet.getContent().isEmpty()) {
tweetService.createTweet(tweet.getContent(), principal);
}
}
#GetMapping("/")
public String goToIndex(Model model){
model.addAttribute("tweet",new Tweet());
return "overview";
}
And i have server.context-path=/api
I have one more additional question to this topic. When i wanted to redirect it to another page i was getting a blank page. Not an error not an exception just a blank page. Any help ? I m new to this.
Yes, this is possible using ajax. I would recommend doing it using jQuery though. So, if you would like to submit your form and stay in the same page, you could do the following.
HTML
<form id="tweet-form" th:action="#{/tweets/tweet}" th:object="${tweet}" method="post">
<div class="row">
<div class="col">
<input type="text" th:field="*{content}" class="form-control" placeholder="What's happening? Tell us!">
</div>
<div class="col">
<input id="submit-form" class="form-control" type="button" value="Submit" />
</div>
</div>
</form>
Changes:
Added an id to the form.
Added an id to your input.
Change submit input's type for button.
jQuery
$('#submit-form').on('click', function() {
var form = $('#tweet-form');
$.ajax({
url: form.attr('action'),
data: form.serialize(),
type: post,
success: function(result) {
// Do something with the response.
// Might want to check for errors here.
}, error: function(error) {
// Here you can handle exceptions thrown by the server or your controller.
}
})
}
Controller
#PostMapping("/tweet")
#ResponseStatus(CREATED)
public Tweet tweet(#Valid #ModelAttribute("tweet") Tweet tweet, Principal
principal, BindingResult result) {
if(result.hasErrors()){
// Throw an exception or send a null Tweet.
}
if (!tweet.getContent().equals(null) && !tweet.getContent().equals("") && !tweet.getContent().isEmpty()) {
tweetService.createTweet(tweet.getContent(), principal);
}
// You are returning a Tweet, so you must return something.
return tweet;
}
Your controller pretty much stay the same. Just remember to return something.
Your example doesn't show what the tweet() method returns. It should return a Tweet object but doesn't have any return value. What are you attempting to do with that return value? If you're not handling it with Javascript someway, then get rid of #ResponseStatus(CREATED) and return a either a Model or a String pointing to your html file, like so:
#PostMapping("/tweet")
public String tweet(#Valid #ModelAttribute("tweet") Tweet tweet, Principal
principal, BindingResult result) {
if(result.hasErrors()){
//do somethign
}
if (!tweet.getContent().equals(null) && !tweet.getContent().equals("") && !tweet.getContent().isEmpty()) {
tweetService.createTweet(tweet.getContent(), principal);
}
return "redirect:/name-of-html-file";
}
reference
If you want thymeleaf to handle the tweet and the HttpStatus you could instead return something along the lines of
ModelAndView model = new ModelAndView("your-view");
model.addAttribute(tweet);
model.setStatus(HttpStatus.CREATED);
return model;
I have a data base which contains some items. I want to create a form which edits item with some id. I did it, form opens fine. Adress is /itemproject/edit_item/{id} Problems start when I'm trying to activate POST method. Instead of directing me to page with item list (/itemproject/view_items) programm sends me to /itemproject/edit_item/edit_item. itemproject is context path (for example).
#RequestMapping(value = "/edit_item/{id}", method = RequestMethod.GET)
public String editItem(#PathVariable("id") Integer id, Model model) {
Item item;
item = dbService.findItem(item).get(0);
model.addAttribute("item", item);
return "edit_item";
}
#RequestMapping(value = "/edit_item/{id}", method = RequestMethod.POST)
public String editItemComplete(#PathVariable("id") Integer id, #ModelAttribute("item") Item item, Model model) {
dbService.updateItem(item);
model.addAttribute("items",dbService.findAllItems());
return "view_items";
}
dbService works with data base.
I want that programm sent me to list of all items after ediding chosen item and updating it in database.
Here is example of edit form (url: /itemproject/edit_item/{id}
<spring:url value="edit_item" var="formURL"/>
<form:form action="${formURL}"
method="post" cssClass="col-md-8 col-md-offset-2"
modelAttribute="item"
>
<div class="form-group">
<label for="item-stuff">Stuff</label>
<form:input id="item-stuff"
cssClass="form-control"
path="stuff"/>
</div>
<button type="submit" class="btn btn-default">Edit item</button>
</form:form>
This is how my item list page looks (url: /itemproject/view_items)
<body>
<table class="table table-hover">
<tbody>
<tr>
<th>Stuff</th>
</tr>
<c:forEach items="${items}" var="item">
<tr>
<td>${item.stuff}</td>
</tr>
</c:forEach>
</tbody>
</table>
</body>
From Spring docs:
In Spring MVC you can use the #PathVariable annotation on a method
argument to bind it to the value of a URI template variable
That means that #PathVariable annotation is suitable when you use the GET method because when you use GET method you can pass your query string.
Instead, try to use #RequestBody in order to try to bind your POST HTTP body message to your parameter
For example:
#RequestMapping(value = "/edit_item", method = RequestMethod.POST)
public String editItemComplete(#RequestBody String body) {
//in here you'll have to pull the body content
return "view_items";
}
Let's say that you're sending an Integer id on HTTP POST body, then you can pull the data from the body like this:
#RequestMapping(value = "/edit_item", method = RequestMethod.POST)
public String editItemComplete(#RequestBody String body) {
ObjectMapper objectMapper = new ObjectMapper();
try {
idJson = objectMapper.readTree(body).path("id").asInt();
} catch (IOException e) {
e.printStackTrace();
}
return "view_items";
}
assuming that you're sending json from client to service.
Rather than loading the items and returning the view_items template, you can return "redirect:/itemproject/view_items" and that will cause your handler for view_items to be invoked, which will load the items etc.
I am still relatively new to springMVC, I currently have some code, that will take an input from a <form:input> on a jsp page, and create different lists depending on the input(providing I enter the correct String). I would like to transition this into a button instead, so I could have four buttons that will return a different String, for example "one", "two", "three" and "four". That way there is no typing needed from the user.
I see that there is a <form:button> available but I do not know how I could return the String value from this. Also I have looked into angularJS and seen that you can call a function onClick. But again, I don't know what the implementation would have to be to tie it into my Controller. I am just not really sure how I can implement this. Any help would be appreciated.
This is what I have being implemented at the moment :
<form:form commandName="input">
<label>Enter Value</label>
<form:input path="listType" class="inputbox" />
<br>
<input type="submit" class="button" value="Enter" />
</form:form>
This takes the input and stores it in an object :
#Controller
#SessionAttributes("input")
public class EventController {
#RequestMapping(value = "/event", method= RequestMethod.GET)
public String displayEvent (Model model) {
AccessInput userInput = new AccessInput();
model.addAttribute("input", userInput);
System.out.println("finished get method");
return "event";
}
#RequestMapping(value = "/event", method= RequestMethod.POST)
public String processEvent(#ModelAttribute("input")AccessInput userInput) {
System.out.println(userInput.getListType()); //just so I know what value it has
return "redirect:results.html";
}
This is the controller that creates my list based on the string that I pass through to the object
#RestController
#SessionAttributes("input")
public class ReportController {
#RequestMapping(value="/events")
public List<Appliance> getEvents(#ModelAttribute("input")AccessInput userInput) {
List<Appliance> events = new ArrayList<>();
events = ProcessChoice.ofList(userInput.getListType());
System.out.println(userInput.getListType());
return events;
}
}
Edit:
Just to note I have resolved this, I followed the example given by Vipin Dubey, I had to change my controller. I removed the POST method and added in a #RequestParam as a parameter, and redirected the buttons on the event.jsp to "results.html?input=one" then took this value and added it to my model to store it in the session.
#Controller
#SessionAttributes("URLparam")
public class ResultController {
#RequestMapping(value = "/results.html", method = RequestMethod.GET)
public String buttonSelect(Model model, #RequestParam("input")String input) {
model.addAttribute("URLparam", input);
System.out.println(input);
return "result";
}
}
You have two options :
1. Short and recommended way :
Use a link and style it as a button and you can directly call your controller
<a class="btn" href="/events?input=one">One</a>
<a class="btn" href="/events?input=two">two</a>
<a class="btn" href="/events?input=three">three</a>
<a class="btn" href="/events?input=four">four</a>
2. Use jQuery or JavaScript to submit the form based on clicked button using a hidden input field in your form
<!-- Buttons with classes -->
<div id="target">
<button class="one">One</button>
<button class="two">two</button>
<button class="three">three</button>
<button class="four">four</button>
</div>
<!-- Your form -->
<form:form commandName="input" id="myForm">
<input type="hidden" name="inputbox" id="inputbox" value=""/>
</form:form>
// You will have to do this for each of the button which is not a recommended way
$( ".one" ).click(function() {
$('input[name="inputbox"]').val("one");
//var a = $('input[name="inputbox"]').val();
//alert(a);
$( "#myForm" ).submit();
});
By using Spring MVC + Maven + Hibernate I'm trying to build a Spring MVC form that has both an "Add To Cart" button, as well as a "Add to Favourites" button. Whenever one button is pressed, the other one returns null as shown in the code below.
Both buttons are type=submit and I'm treating them in the code below. The problem I'm having is that the "Add to Favourites" case is always resulting into an uncaught exception (redirecting me to the "Internal Error" page).
I'm wondering if maybe there's an elegant way to treat each button press in a form separately, without having lots of if - statements for each button.
The HTML file has the following items declared in the form's structure:
<c:if test="${empty readOnly}">
<input type="number" value="1" name="quantity" class="input-mini"/>
<button class="btn btn-primary" type="submit" name="addToCart"><i class="icon-shopping-cart icon-white"><jsp:text /></i> Add</button>
<button class="btn btn-secondary" type="submit" name="favourite"><jsp:text /> Favourite This!</button>
</c:if>
And I'm using the following Controller method:
#RequestMapping(value = "/submit", method = RequestMethod.POST, produces = "text/html")
public String submit(HttpServletRequest request, Model uiModel) {
init(uiModel);
String id = request.getParameter("product-id");
String quantity = request.getParameter("quantity");
if(!request.getParameter("addToCart").toString().equals(null))
{
if (StringUtils.isNotBlank(id) && StringUtils.isNotBlank(quantity)) {
shoppingCartServiceLocal.addToShoppingCart(shoppingCart, id, quantity);
}
}
if(!request.getParameter("favourite").equals(null))
{
//ADD TO FAVOURITE
}
return "redirect:/items/" + id;
}
I might be missing something obvious as I'm still learning these. Any help would be greatly appreciated.
Use the param attribute to specify which method to use for which button.
#RequestMapping(value = "/submit", method = RequestMethod.POST, params = "addToCart")
public String addToCart(HttpServletRequest request, Model uiModel) {
//your code
}
#RequestMapping(value = "/submit", method = RequestMethod.POST, params = "favourite")
public String addToFavorites(HttpServletRequest request, Model uiModel) {
//your code
}