Spring MVC ajax re-rerendering user interface duplication - java

First of all I am mainly with a JSF background.
I have started recently studying Spring MVC. One thing that is bothering me is the ajax re-rendering when using Spring MVC and JQuery.
Let's imagine that I have defined a complex form in my people.jsp view:
<c:forEach var="person" items="${people}">
<table>
<tr class="trPersonClass">...</tr>
<tr>...</tr>
</table>
</c:forEach>
And I have a refresh button below. When the refresh button is clicked I want with ajax the people to rerender.
function refreshButtonClicked() {
$.ajax({
type: "GET",
url: "ajax/loadPeople.do"
}).done(function( msg ) {
//WHAT SHOULD I DO HERE???
}
});
So what I should do there? I have already defined how the people rendering should like with the c:forEach tag in my jsp. I don't want to repeat it again. I don't want to duplicate user interface code at both places - in the JQuery done callback and with JSP tags in my views. This is error prone in my opinion.
Please explain me kindly what I am missing here.

First of all, Spring MVC is very flexible. You can have backend handlers that return HTML generated by a view engine, you can have a handlers that returns JSON/XML/ProtocolBuffers/etc. and use client side rendering engines like Mustache etc. to display the page in the browser, or you can combine the two in the same application.
If you want to generate HTML on the server, Spring MVC allows you to use different template engines to do that. You can use JSP, Freemarker, Velocity etc. In order to do that, it uses a ViewResolver abstraction, and in your code you only have to deal with the ModelAndView API.
More details on ViewResolver can be found here: http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html
Based on your question it sounds like you have a backend that use JSP to create the html server side. In order to update only the table and not reload the entire page when a user clicks a refresh button, you could for example have a handler that returns only the html table like so:
#RequestMapping("/table")
public ModelAndView renderTable() {
List<People> people = peopleService.findAllPeople();
return new ModelAndView("/people", "people", people);
}
I'm also assuming you have another handler that returns the main page where the table is embedded via ajax.
<body>
...
/* Content of div will be populated via ajax*/
<div id="myTableContainer" />
...
</body>
The javaScript for this would be something like:
$(function() {
var myTableContainer = $("#myTableContainer");
var renderTable = function(container) {
$.get("/table", function(data) {
container.empty().html(data);
}
};
/* This is called on document ready */
renderTable(myTableContainer);
/* Use the same renderTable function when the refresh button is clicked */
$("#refreshButton").click(function() {
renderTable(myTableContainer);
});
}

Basically, I see 2 options:
Always load the table using ajax, even on the first rendering (table creation code only in your javascript function)
Modify ajax/loadPeople.do to return an already rendered table instead of a Json list. You could then factor the people table rendering code in a JSP Tag file or use some templating library (tiles, etc.) to reuse that JSP fragment.

Related

How to update data view automatically in Play Framework?

I'm getting start with Play Framework, however it does not have any decent guide to teach what I wanna do.
I have a service that get Memory and disk statistics, I'd like to load/call this service automatically and pass the values from the controller to the view.
Anyone could provide me any tutorial or tips?
So many recipes for that meal! When you say automatically, I am assuming you mean without user interaction. So your web page will need a way to initiate that update, probably via a javascript timer or more old-fashionedly via http meta refresh. In the case of the javascript timer (perhaps setTimeOut or setInterval, each time it "fires" you would use an ajax call to your controller API which would return the data in JSON which you then insert into your page. Pseudo javascript code:
on timer event ->
ajax.GET '/api/monitor' (data) ->
if data.success
update $("#results") with data.statistics
A very simple view might just have:
#()
#main() {
<script src="your javascript.js" type="text/javascript">></script>
<div id="results">
</div>
}
and a controller method to talk to, along the lines (again pseudocode) of:
def apiMonitor = Action {
Ok(Json.obj(
"success" -> true,
"statistics" -> models.statisticsMethod()
))
}
In this case your play view would be a simple container, and the front end work is not really done in the template.
Using the refresh method, your controller could return a view each time, controller Scala pseudocode:
def apiMonitor = Action {
Ok(view.html.monitor(models.statisticsMethod()
}
and a view to format:
#(statistics:List[Statistic])
#main() { <!-- where main generates something with the meta refresh in -->
<table>
<tbody>
#statistics.map { statistic =>
<tr><td>#detail.attribute1</td><td><#detail.attribute2</td></tr>
}
</tbody>
</table>
}
There are lots of ways to design such things. The above is incomplete but covers some points you might need. A very useful place to work from is one of the templates on the LightBend Website where there is working code to play with.

Passing json object via ajax from jsp to javascript

How can pass json values from jsp to javascript as object via ajax?
I can not use global js variables in jsp because this will lead to json content to be visible in page's source
Here is the scenario that I want to achieve:
url of jsp is opened in browser.
Data is being created in scriptlet and coverted to JSON format
json is "sent" to javascript as object
From above scenario, i understand that javascript must initiate the ajax call to jsp.
The issue with this, that jsp's code will be invoked 2 times:
When page is opened in browser - data is prepared
on each ajax call same code will be called again
Constrains: No jquery, no other libs, no servlets, no additional jsps. :(
EDIT:
There is additional problem, I need to pass multiple json objects to javascript.
I wont be able to do it with response.getWriter().write();
I don't think concatenating all json objects and sending is the correct solution.
The parsing of the received object in javascript http.responseText will be overwhelming.
Why do you need ajax here? If you know that you need to populate some things from server onto jsp page you can do that through scriplets itself:
EX
<%# page import="com.mypackage.PersonDAO" %>
<html>
<body>
<table>
<th>Name</th><th>Email</th><th>Contact</th>
<%
List<Person> myList = PersonDAO.getAllPersons();
for(Person person:myList)
{
%>
<tr>
<td><%=person.getName()%></td>
<td><%=person.getEmail()%></td>
<td><%=person.getContact()%></td>
</tr>
<%}%>
</table>
</body>
</html>
This is a very simple example. You can do more complex things using JSTL.. :)
So there is no jquery, no Servlets, no ajax and no extra jsp's :)
UPDATE
Since you want data in your javascript before page loads you can use jQuery's holdReady() method.
$.holdReady( true );
$.get( url, function() {
// Perform something
$.holdReady( false );
});
See but all modern browsers have developer tools like firebug for mozilla, so any ajax call made will be trapped by them. The only way you can secure them is my encrypting them.. which will complicate things for you... IF you can explain the scenario you are trying to implement may be I can come up with it..

Dynamic JSON urls with JSP and Spring-mvc

I would like to pass a variable wordId through JSON GET to Spring-mvc Controller in my webapp. I have no problem with static url to work with json but I do not know what is best practice to do it with dynamic/parametric urls.
Controller part:
#RequestMapping(value="/delete/{wordId}", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteWord(#RequestParam ("wordId") Long wordId, Principal principal) {
wordService.deleteWord(wordId, principal.getName());
}
JSP part:
<c:choose>
<c:when test="${not empty accountWords}">
<c:forEach items="${accountWords}" var="word" varStatus="status">
<li class="word">
<input type="checkbox" name="word" class="word_checkbox" value="" />
<span>${word.word}</span>
<s:url value="/words/delete/${word.wordId}" var="delete_word"></s:url>
<img src="resources/gfx/delete.png" />
</li>
</c:forEach>
</c:when>
</c:choose>
jQuery part so far:
$("li.word a").click(function(e) {
e.preventDefault();
var deleteUrl = ...
$.getJSON(deleteUrl, function() {
});
});
Could you tell how should my jquery part look like to pass wordId variable to controller? I can get url from href attribute of a tag but i would like to have relative url. I'm stucked...
UPDATE:
$("#testJSON").click(function() {
$.getJSON("admin/json.html", function(w) {
$('#span_json').html("w.wordId + "<br>" + w.word);
});
});
Since the wordId is part of the URL, you should be using the #PathVariable annotation instead of #RequestParam.
Also, since you asked about best practices, I should point out that it's not a good practice to use the HTTP GET method for actions that aren't idempotent. In other words, you shouldn't use GET for actions that make a change to data on the server-side, such as deleting records from the database.
The proper HTTP method for performing a record deletion is the HTTP DELETE method. Some older browsers don't support DELETE, so you'll find a lot of code out there that does a POST for deletion instead. I don't think that's much of a problem anymore though. See http://annevankesteren.nl/2007/10/http-method-support for more detail.
Using DELETE instead of GET isn't just a good idea for the sake of "doing things the right way"... it can actually help you avoid some nasty problems. There are browser plugins that will speed-up people's experience on the web by pre-fetching all links on a page and storing them in their local cache. If a user has one of these plugins installed the plugin will "click" on every delete link on your page! Also, if you're building a public-facing application, search engine crawlers will also follow your delete links. I've seen this happen in the real world, so trust me it's a real concern!
Another RESTful best practice is to use URLs that follow the pattern of /noun/{id}, with the HTTP method serving as the verb. So, instead of /delete/{wordId} with a GET, it would be better to go with /word/{wordId} with a DELETE.
With all of my suggested changes your code would look like this:
Controller
#RequestMapping(value="/word/{wordId}", method = RequestMethod.DELETE)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteWord(#PathVariable ("wordId") Long wordId, Principal principal) {
wordService.deleteWord(wordId, principal.getName());
}
Unfortunately, the jQuery and JSP become a little trickier when you use DELETE instead of GET. GET is really tempting because you can just build a link, as you did like this:
<img src="resources/gfx/delete.png" />
To get the browser to use DELETE instead, you either need to have a form whose method is DELETE, or you need to invoke some JavaScript that does an Ajax DELETE. (Since you're already using Ajax, that's the technique I'll go with.) I'd start by changing your link to a button:
<button class="delete-button" id="delete_${delete_word}"><img src="resources/gfx/delete.png" /></button>
This creates a button that stores the id of the word you want to delete in the id of the button itself. Somehow you need to associate the id of a word to delete with every button, and this is one way to do it. I've seen other people put the id in a hidden span next to the button. (To be honest, I've never loved either of these techniques, and I'm hoping somebody follows up my answer with a better way to do it.)
Anyway, with that change in the body of your JSP you'll also want to add some jQuery that handles the click of all delete buttons. (Notice I put a class on the button called "delete-button" so that it would be easy to reference in jQuery.)
jQuery:
$(".delete-button").on("click", function() {
var wordId = $(this).attr("id").substring("delete_".length);
$.ajax({
type: "DELETE",
url: "/word/" + wordId,
success: function() {
// Maybe put some code here that deletes the <li> ?
}
});
});
Notice how I extracted the word id from the id attribute of the button that was clicked:
var wordId = $(this).attr("id").substring("delete_".length);
Of course you could also do it this way:
var wordId = $(this).attr("id").substring(7);
I prefer the first way of doing it because it self-documents what the substring is doing. In the second example the number 7 is a magic number that doesn't explain what's happening.

JSP page values are not getting populated after getting values from JSP popup window

I am passing JSP values to JSF's backing bean. Once I get the values in bean, then I am trying to assign values to inputText fields with setters method, something like this.
public void testProcess(){
empBean.setEmpName(empBean.getEmpId());
}
testProcess method is called in the action of the JSP page.
My question when I set the value in the bean, my JSF page's values are not getting populated. Do I need to explicitly refresh my JSF page, if so how could I do that?
Yes, you need to refresh the main page. What happens on the server will not automatically make something happen on the client (browser).
One fairly common pattern for this type of operation is to have the popup do the form post using ajax (easy with many javascript frameworks like jQuery). See http://jquery.malsup.com/form/ for a nice example using the jQuery form plugin. In the response handler for the ajax-call, you reload the main page (using the window.opener property) and close the popup. In the example with the jQuery Form plugin, you would do something like:
<script type="text/javascript">
// wait for the DOM to be loaded
$(document).ready(function() {
// bind 'myForm' and provide a simple callback function
$('#myForm').ajaxForm(function() {
// reload main page
window.opener.location.reload();
// close popup
window.close();
});
});
</script>
The reason you want to submit the form using ajax is that you want to wait to refresh the main page until the post is completed and doing a regular post will cause the popup to reload, which in some browsers will invalidate the window.opener property, making it impossible to reload the main page.

Loading a popup using ajax

I have a jsp page which should load a popup using ajax. The content of the page is determined by form filled by user.
Something like this:
javascript:
ajax('getPage.action', 'content_id', 'form_id');
foo.jsp:
<div id="content_id"></div>
<form id="form_id">
...
</form>
java/spring:
#RequestMapping("getPage.action")
MyController extends AbstractCommandController {
RealDto dto = (RealDto)command;
...
return new ModelAndView("foo", data);
}
The most difficult part for me is how to send the form data easily as an ajax call. Can I use jQuery here? The form changes dynamically so it would be quite bothersome to list all the fields of the form.
Would it help to use Springs XT (which I never have)?
Yes, you can use serialize to trivially convert the form to send the data.
$("#form1").submit(function() {
$.get("/desiredURL", $("#form1").serialize(), function(response) {
// send response data to a popup
}
}
You can use get or post to send the data.
For the popup I like facebox, but there's loads of choices.
jQuery form plug-in can help you easily transform a regular form to an Ajax one. You only need a single line of code:
$("#myform").ajaxForm(
{beforeSubmit: validate, success: showPopup} );
I don't know about jQuery, but for prototype this is easy:
new Ajax.Request('getPage.action', {
parameters: $('form_id').serialize(true),
onSuccess: someMethod
);
Check out the Prototype API docs.
This page has the same information for jQuery: http://docs.jquery.com/Ajax

Categories