I am having trouble nailing down the best method for passing data from a Java backing/managed bean to a jQuery/Javascript component such as Highcharts, so that my web app produces/displays data in a dynamic, real time way. I am pretty solid on my Java side of things but I have a pretty limited knowledge of JavaScript/jQuery which is obviously where I am falling down. So far as I have read, the best way is to Ajaxify a hidden field on my web app and pass a JSON object or string? in to it and then pass that value into my JS component.
Firstly this seems a bit labour intensive as I would have an Ajax call to update the JSON data and then a setInterval call to re-read the data into the JS component? I was hoping that I could pass the data straight into the JS component…
Either way could someone just firm up my knowledge and tell me a good tried and tested method, if different from above… Guides/Demo’s would also be massively appreciated!!
I also use Primeface’s 2.2.1 if this will affect a suggested methodology?
Cheers
Ally
UPDATE:
Code is below but I just want to describe what I am trying to achieve quickly: Effectively I am trying to implement a dynamic Highcharts chart, using a simple count++ function from my backing bean. Obviously further down the line I will be using a real-time feed to provide this data but at the moment I am just trying to get Highcharts to work based of changing information from my JSF backing bean.
Here is my simple count function and conversion to JSON (I am not sure if the JSON method is really necessary since only 1 value(int) is being passed, but I would like to retain this method as I am sure I will be using more extensively on other parts of the web app):
public class TestBean {
private int output;
public TestBean() {
output = 1;
}
public int getOutput() {
return output;
}
public void setOutput(int output) {
this.output = output;
}
public void update() {
setOutput(getOutput() + 1);
}
public void prepareChartDate() {
// Produce you JSON string (I use Gson here)
RequestContext reqCtx = RequestContext.getCurrentInstance();
reqCtx.addCallbackParam("chartData", new Gson().toJson(output));
}
}
Highcharts External JS File, again its worth noting that I have maintained the series function at the bottom of the chart to build/populate the graph before I start appending values obtained from the JSF Beans:
Highcharts.setOptions({
global: {
useUTC: false
}
});
var chart;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
backgroundColor: "#F8F0DB",
renderTo: 'containerHigh',
defaultSeriesType: 'area',
margin: 10,
marginLeft:30,
marginBottom:17,
zoomType: 'y',
events: {
load: updateChartData
}
},
title: {
text: 'Feed Flow Rate '
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: ''
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'<br/>'+
Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
plotOptions: {
area: {
fillColor: {
linearGradient: [0, 0, 0, 100],
stops: [
[0, Highcharts.getOptions().colors[0]],
[1, 'rgba(2,0,0,0)']
]
},
lineWidth: 1,
marker: {
enabled: false,
states: {
hover: {
enabled: true,
radius: 5
}
}
},
shadow: false,
states: {
hover: {
lineWidth: 1
}
}
}
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i++) {
data.push({
x: time + i * 10000,
y: 50 * Math.random()
});
}
return data;
})()
}]
});
});
And the inline JS Function held on my XHTML page:
This works:
function updateChartData(xhr, status, args) {
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime()
y = 50 * Math.random();
series.addPoint([x, y], true, true);
}, 1000)
//parse it, process it and load it into the chart
}
but when I try to pass my bean value:
function updateChartData(xhr, status, args) {
var jsonString = args.chartData
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime()
y = jsonString
series.addPoint([x, y], true, true);
}, 1000)
//parse it, process it and load it into the chart
}
That doesnt work…
Also I’ve been trying both remoteCommand and Poll to get the chart to work, neither of which I have been successful with:
<h:form>
<p:commandButton value="update" action="#{testBean.update}" update="beanvalue"/>
<h:outputText value="#{testBean.output}" id="beanvalue"/> <br />
<h:outputText value="#{testBean.output}" id="chartValue"/> <br />
<p:commandButton value="Load" type="button" onclick="fetchChartData();"/>
<p:remoteCommand name="fetchChartData"
action="#{testBean.prepareChartDate()}"
oncomplete="updateChartTest(xhr, status, args);"/>
</h:form>
As I’ve said before Bhesh, your help is massively appreciated and anymore would be great!
Cheers
Ally
If you are using PrimeFaces 2.2.1 then it should be pretty easy to acheive what you are trying to do.
PF has a component
p:remoteCommandwith which you can Ajaxicaly invoke a managed-bean method.And in the method
prepareChartData()you produce your JSON string and useRequestContextprovided by PF to send it back to client:And in the Javascript callback function
updateChartData(xhr, status, args)you can process the JSON response and load into the chart:And to periodically update the chart just use the Javascript
setIntervalorsetTimeoutand pass thenameof theremoteCommandwhich is actually a Javascript function.That’s how I do it.
PF also has another component
p:pollwhich makes it easier to implement live charts.Update:
You got it wrong. On
What you need to do is on document-ready render the chart first and then start you poll.
The
p:pollcallback functionupdateChartData(xhr, status, args)needs be global so that the poll can call it ononcompleteevent.And when you are using poll you do not need the
setTimeoutorsetInterval.Update 2:
First of all, in
updateChartDatafunction you are supposed to update thechartthat you created:Next,
updateChartDatais callback function so don’t call it yourself, it is called by the remote-command every time the request is complete.And, give the remote-command a separate form of it’s own:
Note in
oncomplete="updateChartTest(xhr, status, args);"in your code the callback function should beupdateChartTestinstead ofupdateChartTest.Trigger the ajaxical polling after the chart is done loading:
For testing only, trying returning a random value from you managed-bean: