Im looking for a little help on getting my JQuery/Ajax call to return a List from a Struts action and populate a DIV with the list elements using s:iterator.
I have the following JQuery
function lookupCustomerJs() {
alert("lets start");
$.ajax({
type: "POST",
url: "lookupCustomerAjax",
data: $('#lookupCustomer').serialize(),
success:function(response) {
alert("do stuff");
$('div#custList').replaceWith($(response).find("div#custList"));
},
failure:function(response) {
alert('Ajax call failed');
},
error:function(response) {
alert(exception);
}
});
}
I have a DIV within my page which I then want to iterate the list through
<div id="custList">
<s:iterator status="stat" value="customerList" var="customer">
<s:param name="custFName" value="%{customer.firstname}" />
</s:iterator>
</div>
And my Action method which IS called, because when I debug, the debugger goes through the code.
private List<Customer> customerList;
public String lookupCustomerAjax() {
dummyData();
return SUCCESS;
}
This successully calls my Action method, but all I get is the "lets start" alert, then nothing else, no errors, nothing!
So I'm guessing it's just the jQuery/Ajax success:function(response) { not fireing correctly, but can't see why.
It is probably the "lookupCustomerAjax" is an invalid url or file name. You should try adding the extension.
Also, for troubleshooting, you should console.log(response) in your succession to see that you are actually get the result.
Related
I would like to know how to create forms that uses th:object for each object looped in a th:each. For example, I have the following code.
HTML
<th:block th:each="store: ${stores}">
<form th:object="${store}" th:action="#{/modify-store}">
<input th:field="*{idStorePk}"/>
<input th:field="*{name}"/>
<input th:field="*{phoneNumber}"/>
<button type="submit">Modify</button>
</form>
</th:block>
Controller
#RequestMapping(value = "/stores")
public String getIndex(Model model) {
model.addAttribute("stores", storeService.getAllStores());
return "store";
}
So, I would like to add a form for each object, but it seems that it is not possible and I get the following error.
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'store' available as request attribute
So, I decided to add a #ModelAttribute in my controller, but can't get to return the actual store.
#ModelAttribute("store")
public Store getStore(Store store) {
return store;
}
With this approach all my forms have null values. I also tried to add a #PathVariable, but can't see to bind it using th:object. Is there a solution for this?
So for anyone stuck at a similar problem. I find out a work around that might help you out. First, you can't use th:object, it simply won't cut it. Instead, do the following.
<th:block th:each="store: ${stores}">
<form class="store-form" th:action="#{/modify-store}">
<input th:name="idStorePk" th:value="${store.idStorePk}"/>
<input th:name="name" th:value="${store.name}"/>
<input th:name="phoneNumber" th:value="${store.phoneNumber}"/>
<button class="submit-button" type="submit">Modify</button>
</form>
</th:block>
Then just add something similar to the controller.
#PostMapping(value = "/modify-store")
#ResponseBody
public boolean deleteEntry(#ModelAttribute Store store) throws Exception {
// Your code here...
return true;
}
If you want to send it asynchronously then you will need to add some JS code in order for it to work. It should look something like the code below.
const forms = document.querySelectorAll('.store-form');
forms.forEach(form => {
form.addEventListener('submit', event => {
// Stop the normal form submit triggered by the submit button
event.preventDefault();
const formInputs = form.getElementsByTagName("input");
let formData = new FormData();
for (let input of formInputs) {
formData.append(input.name, input.value);
}
fetch(form.action,
{
method: form.method,
body: formData
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error.message))
.finally(() => console.log("Done"));
});
You're sending stores in your controller in model-attribute and on your second controller where you're submitting your form you're using store that's the reason you're getting this error. So correct the spelling error on any one of your controller. Like this :-
#RequestMapping(value = "/stores")
public String getIndex(Model model) {
model.addAttribute("stores", storeService.getAllStores());
return "store";
}
And Your second controller where you're submitting your form will be like this -
#ModelAttribute("stores")
public Store getStore(Store store) {
return store;
}
Ok so I'm submitting a simple form to my Spring Controller through jQuery. Here is the code:
<form id="addNote" role="form" action="addNote" method="POST">
<div class="form-group error">
<label for="note">Enter your Note </label>
<textarea rows="3" cols="50" name="note" class="form-control"
id="note"></textarea>
</div>
<div class="alert alert-danger" style="display: none">
<strong>Error!</strong> Text length must not exceed 100 characters
</div>
<button type="submit" class="btn btn-default">Save Note</button>
$(document).ready(function(){
$("#addNote").submit(function(e){
e.preventDefault();
var formObj = $(this);
var formURL = "addNote";
var formData = $("#note").val();
$.ajax({
url: formURL,
type: 'POST',
data: formData,
success: function(response){
alert(response);
},
error: function(response){
}
});
});
});
And the Controller method:
#RequestMapping(value="/addNote", method=RequestMethod.POST)
public Vector<String> addNote(Locale locale, Model model, HttpServletRequest httpServletRequest, HttpSession httpSession){
String note = httpServletRequest.getParameter("note");
notes.add(note);
ModelAndView mv = new ModelAndView("notes");
mv.addObject("thenotes", notes);
return notes;
}
I need to return the notes object to the jQuery so that I can display it's data as output. But this is the error I'm getting in the Chrome console:
So apparently there is a problem in the path. I have tried changing var formURL = "addNote"; to var formURL = "assessment/addNote"; in the jQuery but it doesn't work.
But for some reason if I change return value of addNote() function in the Controller to ModelAndViewand return mv then it works but it's not the response in the jQuery I need.
First of all You are using AJAX, so You can't return data using modelAndView.You have to return data as xml/json.
In Your javascript code add the following function:
function getContextPath() {
return window.location.pathname.substring(0, window.location.pathname.indexOf("/",2));
}
reference: How do you get the contextPath from JavaScript, the right way?
Then change You formURL to:
var formURL = getContextPath()+"/addNote";
With the above code requests reaches the controller. Within the controller You have to change Your requestMapping a bit:If You want to return some simple message then You can return it as a string(I am not sure whether it is the best way, but this is how I do it)
#RequestMapping(value = "/addNote", produces=MediaType.APPLICATION_XML_VALUE, method = RequestMethod.GET)
#ResponseBody
public String showNote(){
System.out.println("saving note..");
return "<response>Example</response>";
}
If You want to return a Vector or java object to JQuery, then the best idea is to use jackson-mapper or some similar library, You can find info easily with google.A simpler(not necessarily better solution) would be to define a method that would create the xml String by looping through the vector, sth like:
<notes>
<note>note1</note>
<note>note2</note>
</notes>
and return it as a String from controller, and then process xml within JQuery.
I also learn spring, so if someone knows a better solution, I will be happy to read it ;-)
Regards,
Mikajlo8
EDIT:I Have changed the requestMethod to GET, otherwise You have to deal with CSRF TOKENS.If You want to use POST, is is easy to find on the internet how to deal with csrf tokens.
I'm working on online shopping application using struts 2, mysql , jquery, jsp, bootstrap, gson and tomcat.
I have Java entity called Product, controller action that return json array of products and jsp page that calls that action through ajax and displays all products to user.
What I don't understand is to how display such json array.
I've googled for JQuery Datatables plugin as it propose filtering and pagination, but I don't get how it should be configured, because I want to group information not by product fields, but to group by every product entity like in the following picture:
If there is a better plugins or other solutions please suggest them, but please note that in future development I want to add an image of Product.
Product entity:
public class Product{
private long id;
private String name;
private double price;
private long storeId;
//getters and setters
}
And action controller class ViewAllProducts:
public class ViewAllProducts extends ActionSupport {
#Override
public String execute() throws Exception {
LOG.trace("Start execute");
Collection<Product> products = productDAO.findAll();
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(products,
new TypeToken<Collection<Product>>() {
}.getType());
JsonArray jsonArray = element.getAsJsonArray();
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().print(jsonArray);
LOG.trace("Finished execute");
return null;
}
}
This is my code from jsp page where I do Ajax call for this action:
<%# include file="/WEB-INF/jspf/directive/page.jspf"%>
<%# include file="/WEB-INF/jspf/directive/taglib.jspf"%>
<html>
<%# include file="/WEB-INF/jspf/head.jspf"%>
<body>
<%# include file="/WEB-INF/jspf/menu.jspf"%>
<div class="container" style="width: 40%">
<div id="results"></div>
</div>
<script type="text/javascript">
$.ajax({
type : 'GET',
dataType : 'json',
url : 'product/upload_products',
success : function(products) {
$.each(products, function(index, product) {
$('#results').append(?????);
});
}
},
})
</script>
</body>
</html>
Json array output example:
[{"name":"Amet Ultricies Incorporated","price":679.71,"storeId":1,"id":1},
{"name":"Ut Nisi A PC","price":1133.43,"storeId":1,"id":2},
{"name":"Ligula Limited","price":156.66,"storeId":1,"id":100}]
Use .each to loop over everything and write the values to the page. If each items ID is used as a div ID or class, you can use that to target each product. But without seeing the actual markup, its hard to say how each value will be used.
Youll want to do something similar to this in your success function.
success: function (data) {
$(data.products).each(function (index, item) {
$("#"+item.id+" .name").html(item.name);
$("#"+item.id+" .price").html(item.price);
$("#"+item.id+" .store").html(item.store);
});
},
error: function () {}
});.
Of course, this only works if you have the data already on the page. If you nee to build the entire list of products on the page, I suggest you use a JS template system like Mustache JS with ICanHaz.
http://icanhazjs.com/
i am new to portlet and I have a visit.jsp page with an href tag as follows:
Visit ....
Basically my requirement is that i just have to call a method called methodVisit in a VisitController.java when i click on the href and return back to visit.jsp.
Then in my methodVisit add an attribute called isVisited to my model and return to my visit.jsp page
so my method will have the following line i guess:
VisitController.java
public .. methodVisit(...){
model.addAttribute("isVisited", isVisited));
}
Then when i return on my visit.jsp page i can use this check:
<c:if test="${isVisited}">
Then display this line when href is clicked from visit.jsp page
</c:if>
I have seen the following example when submit button is used:
<portlet:actionURL var="returnToSearchUrl" >
<portlet:param name="ActController" value="returnToSearch" />
</portlet:actionURL>
<input type="button" class="button" value='<spring:message code="button.returSearch" />' onclick="self.location='${returnToSearchUrl}'"/>
#ActionMapping(params = "ActController=returnToSearch")
public void returnToSearch(){
......
}
However no example when using the href one, any advice how to do it with href please?
try this:
Click here!
#Controller
#RequestMapping(value ="/pathtoyourproject")
public class VisitController{
#RequestMapping(value = "/methodVisit")
public ModelAndView methodVisit(...){
ModelAndView mav = new ModelAndVew();
...
mav.addAttribute("isVisited", isVisited);
...
mav.setViewName("visit.jsp");
return mav;
}
Why not to use Ajax and update the link once the Ajax request is completed?
var visitLink = $("a:contains('Visit')");
$(visitLink).click(function(event) {
$.ajax({
url:"www.randomUrl.com",
success: function() {
$(visitLink).hide();
}
});
event.preventDefault();
});
I have a web jsp web application. In one page I need two dropdownlist. When I will select a value from dd1 then second dropdown will be fill according this value. How I can call java function from dropdown 1 change event in javascript or jQuery?
I got example but that is calling jsp page but I need to java method and send parameter what i got from dropdown1
This is my dropdown dd1. So if I select tom I have to related information of tom in dd2.
<td>
<select id="dd1">
<option value="1">john</option>
<option value="2">Tom</option>
</select>
</td>
</tr>
<tr>
<th> Projects </th>
<td>
<select id="dd2">
<option value="1">pp1</option>
<option value="2">pp2</option>
</select>
</td>
I have following code
$(function () {
var ddVal = '';
var dropdown = document.getElementById("dd1")
$(dropdown).focus(function () {
ddVal = $(this).val();
}).blur(function () {
if (ddVal == $(this).val()) {
$(this).change();
}
}).change (function () {
});
For change event of dd1. But I don't know how to call java method from jQuery.
In my application I have a java class where there is a method which return list that I need to load in dd2 dropdown.
Can anyone help me regarding this issue?
You should do such things with AJAX.
JavaScript sends the request, your controller utilizes the Java part to carry out what's needed and then passes back a JSON response, based on which your JavaScript manipulates the page.
EDIT:
For example, the script can issue the following request:
$.ajax({
"type": "POST",
"url": "/ajaxAPI/updatedropdown/",
"data": {
"selected": selectedMenuItemId
},
"success": function (data) {
var menuItems = data.menuItems;
dropDownToChange.updateChoices(menuItems);
}
});
Your controller for such a request might look like:
public class DropDownListController implements Controller {
#Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
MenuItem selected = extractSelectionFromRequest(request);
List<MenuItem> choices = dropDownListService.getMenuFor(selected);
ModelAndView mav = new ModelAndView("dropDownListAjax.jsp");
mav.addObject("menu", choices);
}
// WARNING! Some error checks are missing!
private MenuItem extractSelectionFromRequeset(HttpServletRequest request) {
validateRequest(request);
return dropDownListService.getMenuItemById(request.getAttribute("selected"));
}
// ...
}
And for the view you could have something like:
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
{
"menuItems": [
<c:forEach items="${menu}" var="menuItem">
{
"url": <c:out value="${menuItem['url']}"/>,
"caption": <c:out value="${menuItem['caption']}"/>
},
</c:forEach>
]
}
The client side JavaScript will then receive a response like:
{
"menuItems": [
{
"url": "http://www.example.com/"
"caption": "Home"
},
{
"url": "http://www.example.com/news/list/"
"caption": "News"
},
{
"url": "http://www.example.com/forum/topics/"
"caption": "Forum"
},
]
}
Please note that the above example might not be 100% correct as there have been a while since I last used JSP (and I'm more comfortable with FreeMarker anyways).
Basically, you invoke part of your web infrastructure that, rather than responding with HTML code, passes back JavaScript Objects based on the results of the requested operation.
Since jQuery is in the client side and JSP is on the server side, you don't have the option of directly calling the remote method. The standard way to do this in the world of the Web is AJAX.