Not able to perform AJAX call for MVC contoller - ajax

I just want to use ajax call for my Spring MVC controller but Ajax call not hitting to the controller's method. Am I doing it wrong?
My Jsp Code [ModifyUser.jsp]:
<form name="testForm" >
<table>
<tr><th>User ID</th><td><input id="user_id" type="text" value="AD001"
readonly="readonly"> </td></tr>
<tr><th>Name</th><td><input id="user_name" type="text" value="ABC SBC ">
</td></tr>
<tr><th>E-mail</th><td><input id="user_email" type="text"
value="asd#xyz.com"> </td></tr>
</table>
<form>
<script>
function deleteUser()
{
alert("going to delete user");
$.ajax({
type : "GET",
url : "${pageContext.request.contextPath}/deleteUserReq",
data : {
"usrId" : ${user_id}
},
success: function(data){
//response from controller
alert(data);
}
});
}
</script>
My Controller code:
#RequestMapping("deleteUserReq")
#ResponseBody
public ModelAndView inactiveUserReq(#RequestParam HttpServletRequest
request, HttpServletResponse response, Model model) {
System.out.println("===== going to delete user ===== ");
/*String userChk=reportDAOImpl.inactiveUser(userID);*/
String userChk="success";
System.out.println(" === "+userChk);
return new ModelAndView("ModifyUser","responsetxt",userChk);
}

you should not return model and view with response body,either string
or something that can be converted to json by jackson (Map,ArrayList)
#RequestMapping("deleteUserReq")
#ResponseBody
public String inactiveUserReq(#RequestParam HttpServletRequest
request, HttpServletResponse response, Model model) {
System.out.println("===== going to delete user ===== ");
/*String userChk=reportDAOImpl.inactiveUser(userID);*/
String userChk="success";
System.out.println(" === "+userChk);
//return new ModelAndView("ModifyUser","responsetxt",userChk);
//return string or json
return "success";
}
I hope it helps

URl is not calling deleteUserReq controller
http://localhost:8085/CdfPortal/userModify?usrId=BU941003 [Actual result]
http://localhost:8085/CdfPortal/deleteUserReq?usrId=BU941003 [Required]

Related

Spring boot, Thymeleaf, Ajax, get null object from ajax

I want to get an object from the form right away in ajax. Where object has name, booleans. But after the transfer, in Controller for some reason it comes with null fields.
Here HTML code:
<form id="profileStats" name="profileStats" action="#" th:action="#{/profile/{id}}" th:object="${profileStats}"
method="get">
<div class="photo">
<img src="./static/img/icon.ico" th:src="*{photoPath}" width="200px" height="200px"/>
</div>
<div class="info">
</div>
</form>
Controller, where i send object to HTML:
#GetMapping("/{id}")
public String getProfile(#PathVariable("id") long id, Model model) {
ProfileStats stats = new ProfileStats(userClient.getClient());
model.addAttribute("profileStats", stats);
return "profile";
}
Ajax, where i send object from HTML to Controller:
function setStatistic() {
var $form = $('#profileStats');
$.ajax({
url: window.location.pathname + '/progress',
method: 'GET',
cache: false,
data: $form.serialize(),
success: function (data) {
$('.info').html(data);
if (data.search("done") >= 0) {
stopProgress();
}
},
error: function (e) {
console.log("error", e)
}
});
}
Controller, where i get object from AJAX:
#GetMapping("/{id}/progress")
public ModelAndView getProgress(#ModelAttribute("profileStats") ProfileStats stats) {
ModelAndView modelAndView;
if (stats.isHaveAllMessage()) {
// HERE I GET NULL EXCEPTION
}
return modelAndView;
}
What am I doing wrong?
In debugging console.log($form.serialize()) I get nothing
You should not use ModelAttribute and ModelAndView in your GetMapping method if you want to use this from an AJAX call.
Use a #RequestBody and return a #ResponseBody instead. And in your AJAX call, create JSON from the form data to send and receive.
#ResponseBody
#GetMapping("/{id}/progress")
public ProgressResponse getProgress(#PathVariable("id) String id, #RequestBody ProfileStatsRequestBody requestBody) {
//.. do whatever needs to be done here
return new ProgressResponse(...)
}
With ProgressResponse and ProfileStatsRequestBody 2 new classes that map onto the JSON you want to send/receive.
You may want to include some fields as part of the form so Spring can do the mapping to the respective fields in the ProfileStats object. See the example in here: https://spring.io/guides/gs/handling-form-submission/

Ajax POST call to Spring MVC

This question is follow up of Returning ModelAndView in ajax spring mvc
As the only answer says that we need to return json from Controller not ModelAndView. So the question is
what can be done to return ModelAndView ?
How the page will be rendered:-
will it have to be handled in success section of ajax call
Or Spring Controller will return the page as usually it does in Spring MVC
How the post data from ajax can be read in Controller.
Update 1:
As explained, I tried example. here is my code.
#Controller
public class AppController
{
#RequestMapping(value="/greeting",method=RequestMethod.POST)
#ResponseBody
public ModelAndView getGreeting(#RequestBody String json) throws IOException
{
JSONObject inputjsonObject = new JSONObject(json);
String name = inputjsonObject.getString("name");
ModelAndView modelAndView = new ModelAndView();
String result = "Hi "+name;
modelAndView.addObject("testdata", result);
modelAndView.addObject("user", getPrincipal());
modelAndView.setViewName("greetingHtmlPage");
return modelAndView;
}
// other stuff
}
In above controller method i can get data sucessfully. This method is called from a javascript on home.html. Below is javascript function
function callGreeting(){
var nameData={
name : document.getElementById("name").value
}
var dataInJson = JSON.stringify(nameData);
var csrf_token = document.getElementById("token").value;
$.ajax({
type: 'POST',
url: "greeting",
data: dataInJson,
cache:false,
beforeSend: function(xhr) {
xhr.setRequestHeader('X-CSRF-Token', csrf_token);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
},
success: function (response) {
document.open();
document.write(response);
document.close();
},
error: function (data) {
alert("failed response");
}
}); }
I have the page rendered successfully. But the url of application does not changes from AjaxSpringMVC:8080/home to AjaxSpringMVC:8080/greeting even after new page was loaded. This happens by itself in Spring MVC if using without Ajax.
what can be done to return ModelAndView ?
You can return ModelAndView As usual:
public ModelAndView returnView( Model model ) {
model.addAttribute( "myStaff", "my staff as string" );
return new ModelAndView( "myView" );
}
How the page will be rendered:
You control how it is rendered, .
When you return ModelAndView, the response has an HTML page.
After the Ajax call, you can do $("#container").html(response) or something like that to display the HTML page wherever you want.
In other words, you get a whole html page of content from the controller.
However, I highly recommend that you just return json object and update your view with the json object. Ajax is mostly used to create good user experience by updating part of the view asynchronously, so getting a whole page with Ajax does not make sense to me.
How the post data from ajax can be read in Controller.
There are many ways, I like to send json body directly to controller
#ResponseBody
#RequestMapping(value = "/saveObj", method = RequestMethod.POST, consumes = "application/json")
public String saveObj(Model model, #RequestBody MyObj myObj) {
// do staff..
}

Multiple form submition in spring mvc 3.0

i want to show entered data of user in a registration form (like preview page) to confirm correctness of entered data and if they accept, then that data should go into the database.
here is my controller code:
#RequestMapping( value="/catalogue/FormPreview.action", method=RequestMethod.POST)
public ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command,CatalogueBase catalogueBase) throws Exception {
if(catalogueBase.getTitleNumber()!= null)
{
request.setAttribute("titleNo", catalogueBase.getTitleNumber());
request.setAttribute("title", catalogueBase.getTitle());
request.setAttribute("name", catalogueBase.getName());
request.setAttribute("address", catalogueBase.getAddress());
request.setAttribute("email", catalogueBase.getEmail());
.....
return new ModelAndView("catalogue/catalogueFormPreview","catalogueBase",catalogueBase);
}
else
{
return create(catalogueBase);
}
}
#RequestMapping( value="/catalogue/create.action", method=RequestMethod.POST)
public ModelAndView create(#ModelAttribute CatalogueBase catalogueForm) throws Exception {
ModelAndView mvc = null;
try{
List<CatalogueBase> catalogueBases = new ArrayList<CatalogueBase>(); //getCatalogueBase(request);
catalogueBases.add(catalogueForm);
List<CatalogueBase> catalogueBaseList = catalogueService.create(catalogueBases);
mvc = new ModelAndView("catalogue/catalogueList");
} catch (Exception e) {
e.printStackTrace();
}
return mvc;
}
and I show the preview page as jsp using EL like:
Title NO : ${titleNo}
Title : ${title}
......
......
<a onclick="doAjaxPost();">Confirm Data<span class="icon icon44"></a>
and in the head section of the jsp I am calling ajax like:
<script>
function doAjaxPost() {
var name = $('#name').val();
var education = $('#education').val();
var str = $("#form").serialize();
$.ajax({
type: "POST",
url: "../catalogue/create.action",
data: str,
success: function(response){
alert("Record Added Successfully");
},
error: function(e){
alert('Error: ' + e);
}
});
};
it is showing data on preview page, but after clicking on confirm data, (hyperlink in preview page)
it sends null values to the create method(Second method) please can anyone tell why it's sending nulls and how I can solve this
thanks.
In Preview Page, you are only displaying the text, you need to get your data there as well in preview page either as hidden(or by any other means, like saving in session if much entries are there then etc). so that when you submit after confirmation, you can read all parameters.

MVC3 - parameter value always null

I'm trying to make an "advanced search" view, using two partial views and Ajax. I defined a "SearchFilter" entity having as properties all the available search criteria. On submit in the "_Filter" partial view (the OnSuccess AjaxOption), I need to pass it to the "ListResults" action which updates the "_Results" partial view.
The problem is that I always get a null entity as incoming parameter of the ListResults action.
The code is as follows:
AdvancedSearchView.cshtml
#model MyApp.ViewModels.SearchFormViewModel
#{
ViewBag.Title = "Advanced search";
}
<div id="divFilter">
#Html.Partial("_Filter", Model)
</div>
<div id="divResults">
#Html.Partial("_Results", Model.ResultsList)
</div>
_Filter.cshtml
#model MyApp.ViewModels.SearchFormViewModel
<script type="text/javascript">
function getForm(url, divName) {
var obj = new Date();
url = (url.indexOf('?', 0) != -1) ? url + '&uid=' + obj.getTime() : url + '?uid=' + obj.getTime();
$.get(url, function (data) {
$("#" + divName).html(data);
});
}
</script>
#using (Ajax.BeginForm("Search", null, new AjaxOptions
{
UpdateTargetId = "divFilter",
InsertionMode = InsertionMode.Replace,
OnSuccess="getForm('"+Url.Action("ListResults", "Products", new { myFilter = Model.CurrentFilter}) + "','divResults')"
}, new { id = "idSearchForm" }))
{
<fieldset style="width: 800px; line-height: 1.4em;">
<legend>Configure your search filters</legend>
...
</fieldset>
<input type="submit" value="Rechercher" class="submit" style="width: 280px" />
}
Controller
public ActionResult Search()
{
SearchFilter currentFilter = new SearchFilter();
List<Product> filteredProductsList = repository.FindProducts_Filtered(currentFilter);
return View("AdvancedSearchView", new AdvancedSearchFormViewModel(currentFilter, filteredProductsList/* , necessary select lists */));
}
[HttpPost]
public ActionResult Search(AdvancedSearchFormViewModel model)
{
SearchFilter currentFilter = model.CurrentFilter;
// set the necessary select lists
List<Product> filteredProductsList = repository.FindProducts_Filtered(currentFilter);
return PartialView("_Filter", AdvancedSearchFormViewModel(currentFilter, filteredProductsList/* , necessary select lists */));
}
public ActionResult ListResults(SearchFilter myFilter)
{
List<Product> filteredProductsList = repository.FindProducts_Filtered(currentFilter);
return PartialView("_Results", filteredProductsList);
}
The view model
public class AdvancedSearchFormViewModel
{
// Properties
public SearchFilter CurrentFilter { get; set; }
public List<Product> ResultsList { get; set; }
// some SelectLists
// Constructor
public AdvancedSearchFormViewModel()
{}
public AdvancedSearchFormViewModel(SearchFilter pCurrentFilter, List<Product> pResultsList, /* necessary select lists*/)
{
CurrentFilter = pCurrentFilter;
ResultsList = pResultsList;
// the SelectLists
}
}
I have no doubt I do something wrong, but I cannot see what it is.
The generated HTML markup of the BeginForm is like this:
<form action="/Products/Search" data-ajax="true" data-ajax-mode="replace" data-ajax-success="getForm('/Products/ListResults?myFilter=MyApp.Models.SearchFilter&uid=2622ea0e-d7dc-48fa-b65d-519978ee40b3','divResults')" data-ajax-update="#divFilter" id="idSearchForm" method="post">
The reason you are getting a null value for the myFilter argument of the ListResults action is because this is what you are submitting to the server:
/Products/ListResults?myFilter=MyApp.Models.SearchFilter&uid=2622ea0e-d7...
The default modelbinder is trying to turn the string "MyApp.Models.SearchFilter" into an instance of MyApp.Models.SearchFilter, which it cannot do.
I can't see the code for this model object, but you should try sending each of the parameters individually so that the modelbinder is able to construct an instance of the SearchFilter out of its properties:
OnSuccess="getForm('"+Url.Action("ListResults", "Products", new {
Prop1 = Model.CurrentFilter.Prop1,
Prop2 = Model.CurrentFilter.Prop2,
etc...
})...
Update after comment 1
To answer your question about showing parameter values in the URL, this is how HTTP works. If you do not want to show any parameters sent to the server in the URL, then you will need to do an HTTP POST instead of an HTTP GET.
However, any time your operation is idempotent, you should use an HTTP GET. HTTP POST should be reserved for when the input submission should somehow alter the state of the application. In actuality, I disagree with your using [HttpPost] for your public ActionResult Search(AdvancedSearchFormViewModel model) action method. Since all it is doing is returning data to be viewed, it is an idempotent action.
That said, there is nothing preventing you from breaking this guideline and doing an HTTP POST instead of a GET. Personally, I don't see a problem with the URL parameters. You see them all the time on the web. For example, see the URL for this link.
HTTP does not understand complex objects, only text. To send data for complex objects over HTTP, they need to be broken down into their text parts. To send data like this over an HTTP GET, they need to be in the URL.

Spring portlet mvc Validation fails during submission of the editted form

I have a form with few validations on it.
During new form submission, if validation fails I can see those error messages.
but, during editing the form when I change the field to blank intentionally and submit the form error messages are not shown on Jsp page but I can get the errorcount in controller as 1 .
<portlet:actionURL var="actionUrl">
<portlet:param name="action" value="editCommunity"/>
<portlet:param name="communityID" value="${community.id}"/>
</portlet:actionURL>
<liferay-ui:tabs names="Details" />
<form:form commandName="community" method="post" action="${actionUrl}">
<form:hidden path="id"/>
<div><form:errors cssClass="portlet-msg-error" path="*"/></div>
<table class="manager-detail">
<tr>
<th class="portlet-form-field-label">
<label for="community_label_name"><spring:message code="community.label.name"/></label>
<span class="manager-field-required">*</span>
</th>
<td><form:input id="community_label_name" cssClass="portlet-form-input-field" path="name" size="30" maxlength="80" /></td>
</tr>
My edit controller method.....
rendering edit form
#RequestMapping(params = "action=editCommunity")
public String showEditCommunityForm(final RenderRequest request,
#RequestParam(value="communityID") Long id, final Model model)
throws CommunityNotFoundException {
final ThemeDisplay themeDisplay = (ThemeDisplay) request
.getAttribute(WebKeys.THEME_DISPLAY);
model.addAttribute("community", communityService.getCommunity(id));
return "communityEdit";
}
edited form is submitted
#RequestMapping(params = "action=editCommunity")
public void submitEditCommunityForm(final ActionRequest request,
final ActionResponse response,
#ModelAttribute("community") Community community,
BindingResult result, Model model) throws SystemException, PortalException {
communityValidator.validate(community, result);
if (result.hasErrors()) {
System.out.println("validation errors size..."+result.getErrorCount());
//model.addAttribute("community", community);
response.setRenderParameter("action", "editCommunity");
response.setRenderParameter("communityID", String.valueOf(community
.getId()));
}
}
It is not full code but a block
I have tried couple of things like,
changing the http method from post to POST, but nothing works. Validation perfectly works during form creation, but not during edit.
Am I missing anything? please give me suggestions.
Cheers
Vamshi
Preserving the validation error messages can be a real pain!
I have tried a lot of things - from configuring the redirect behavior of the portlet container to using jsr303 instead of spring validation.
The only solution I have consistently had and success implementing is really ugly:
Do the validation in an action method.
If errors are encountered save the BindingResult/Errors-object with "your own key" in the Spring model and interrupt the action handling.
You are redirected to the render method
There you pick up the Errors-object and put it back to the key where "Spring validation" expects it.
In code this looks something like this:
#ActionMapping
public void invite(#ModelAttribute MyFormBean myFormBean,
BindingResult result, Model model) {
// validate indata
myValidator.validate(myFormBean, result);
// Workaround to preserve Spring validation errors
if (result.hasErrors()) {
model.addAttribute("errors", result);
return;
}
...
}
#RequestMapping
public String showForm(#ModelAttribute("myFormBean") MyFormBean myFormBean,
Model model) {
...
// Workaround to get the errors form-validation from actionrequest
Errors errors = (Errors) model.asMap().get("errors");
if (errors != null) {
model.addAttribute(
"org.springframework.validation.BindingResult.myFormBean", errors);
}
return "myForm";
}
The information stored in the Model under "org.springframework.validation.BindingResult.*" are deleted automatically between the action processing and the render processing, and by preserving it explicitly in "errors" the information will be available to the view.
This is an ugly solution, you have to know more than you want about how the implementation really works, it is counter intuitive and if not properly commented this code could easily be removed by someone not familiar with the problem, but it is not a lot of code and it works.
You can omit the #ModelAttribute in the render phase and retrieve it from the model:
#ActionMapping
public void invite(#ModelAttribute MyFormBean myFormBean,
BindingResult result, Model model) {
// validate indata
myValidator.validate(myFormBean, result);
...
}
#RequestMapping
public String showForm(Model model) {
MyFormBean myFormBean = (MyFormBean)model.asMap().get("myFormBean");
...
return "myForm";
}

Resources