Many JavaScript widgets expect data and options in JSON format. Nowadays, it is really easy to choose a cool widget and wrap it in a composite component. But the first question is how to send an AJAX request and to recieve a response in a proper JSON format.
This question is often raised by JSF users. All what you need is a XHTML facelet like this one
<f:view encoding="UTF-8" contentType="text/html"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:outputText value="#{stationView.getClosestStations(param.longitude, param.latitude)}" escape="false"/>
</f:view>
Please consider the
contentType="text/html" (
application/json will not work here) and
escape="false" in the
h:outputText. The method
getClosestStations() in the bean
StationView produces an JSON output for a list of special Java objects. I advise to use the
Gson library in order to serialize any Java object to JSON. Short example:
String[] strings = {"abc", "def", "ghi"};
Gson gson = new Gson();
gson.toJson(strings); ==> prints ["abc", "def", "ghi"]
The XHTML file above is located under the web context. Say, under the path
/rest/stations.xhtml. Ajax call in your JavaScript code should look like this one:
$.ajax({
url: requestContextPath + '/rest/stations.xhtml',
type: "GET",
data: {
"longitude": x,
"latitude": y
},
dataType: "json",
success: function (data) {
$.each(data, function (i, station) {
...
});
},
error: function () {
...
}
});
Please refer the
jQuery docu for more information regarding
$.ajax. Note: if you omit
dataType: "json", you have to parse the JSON string manually.
success: function (data) {
$.each($.parseJSON(data), function (i, station) {
...
});
}
The response is a pure JSON string (no HTML tags) like this one:
[{"latitude":46.947045,"longitude":7.443922,"distanz":110,"name":"Bern, Bundesplatz"},{....},...]
Need more examples for JSON response in JSF? In one of my next post I will probably explain how to implement a cool autocomplete component without writing too much code.
Good post , say i'm in page1.xhtml that is backed by a jsf bean of viewscope and make an ajax request to stations.xhtml to get a json response , wouldn't that ajax request break my view scope since it is going to a different page ?
ReplyDeleteMK
No, why it should break your view scope? Even if you use the same view scoped bean on the page1.xhtml and stations.xhtml, a new instance of the bean will be created for the stations.xhtml. But the first bean instance for the page1 will still exist. I suggest to use different beans or session scoped beans if you think it will break something.
Deletehi, thanks for that article. wou wrote:
ReplyDelete" Even if you use the same view scoped bean on the page1.xhtml and stations.xhtml, a new instance of the bean will be created for the stations.xhtml. "
i have this situation, but i don't want to create a new instance because data is submitted by ajax before i call stations.xhtml. and the before sended data is now lost, because a new instance was created. how can i do that? thanks in advance.
Very useful article. I wonder if this concept can be expanded further to simplify JSF-REST (non-JAX-RS) front end architecture. I am experimenting with fronting a backing bean to expose it to UI widgets (typically jquery based). With all the new frameworks the model in MVC moves to the client where I believe it should be a happy medium between client and server (model brokering).
ReplyDeleteI also wonder how this compares to JAX-RS with respect to performance?
Cheers.
I think JAX-RS is better, more native and faster because a request doesn't pass all JSF phases (it doesn't go through FacesServlet).
Delete