Thanks in advance for your attention.
I've created a JSF 2.0 custom component to render Google GeoCharts. So, the renderer just writes some javascript and a div at the end.
The component works fine doing that. But my requirement is that the GeoChart should change its values using an ajax request. To do that, i'm using a primefaces command button putting in its attribute "update" the id of the geoChart.
The problem is that the GeoChart is not being updated when the comand button is clicked.
I'm using a maven archetype (myfaces-archetype-jsfcomponents20) allowing the automatic generation of some configuration files. So, I just need to write to classes and annotations. Those classes are the UIComponent and the Renderer.
I'm running this code in GlassFish 3.1 and Mojarra 2.1.6
The code of those classes:
UIComponent:
@JSFComponent(
name = "processum:geochart",
clazz = "org.processum.component.gchart.GoogleChart",
tagClass = "org.processum.component.gchart.GoogleChartTag")
abstract class AbstractGoogleChart extends UIComponentBase {
public static final String COMPONENT_TYPE = "org.processum.GoogleChart";
public static final String DEFAULT_RENDERER_TYPE = "org.processum.GoogleChartRenderer";
public static final String COMPONENT_FAMILY = "javax.faces.Output";
/**
*
* GoogleChartModel
*/
@JSFProperty
public abstract GoogleGeoChartModel getModel();
}
Renderer:
@JSFRenderer(
renderKitId = "HTML_BASIC",
family = "javax.faces.Output",
type = "org.processum.GoogleChartRenderer")
public class GoogleChartRenderer extends Renderer {
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
GoogleChart chart = (GoogleChart) component;
String divId = (String) component.getClientId() + "chartDiv";
GoogleGeoChartModel model = chart.getModel();
ResponseWriter writer = context.getResponseWriter();
writer.write("<script type='text/javascript'>"
+ "google.load('visualization', '1', {'packages': ['geochart']});"
+ "google.setOnLoadCallback(initGeoMap);"
+ "function initGeoMap() {"
+ "var data = google.visualization.arrayToDataTable(["
+ "[");
StringBuilder data = new StringBuilder();
for (String header : model.getHeaders()) {
data.append("\'").append(header).append("\'").append(",");
}
data.deleteCharAt(data.length() - 1).append("],");
for (String[] value : model.getValues()) {
data.append("[");
for (int i = 0; i < value.length; i++) {
if (i == 0) {
data.append("\'").append(value[i]).append("\'");
} else {
data.append(value[i]);
}
data.append(",");
}
data.deleteCharAt(data.length() - 1).append("],");
}
data.deleteCharAt(data.length() - 1);
writer.write(data.toString());
writer.write("]);");
writer.write("var options = {"
+ "region: 'CO',"
+ "displayMode: 'markers'"
+ "};"
+ "var chart = new google.visualization.GeoChart(document.getElementById(\'" + divId + "\'));"
+ "chart.draw(data, options);"
+ "};"
+ "</script>"
+ "<div id=\"" + divId + "\"/>");
}
}
XHTML:
<h:form>
<div id="anotherContent" style="width: 900px; height: 500px;">
<h:panelGroup id="chartCont" layout="block">
<processum:geochart id="chart" model="#{chartBackBean.model}"/>
</h:panelGroup>
</div>
<p:commandButton id="change" value="Cambio" actionListener="#{chartBackBean.change}" update="chart"/>
</h:form>
Some debugging:
The ajax request is triggered adequately. The managed bean updates the GoogleGeoChartModel with new values. Next, the control flow goes to the Renderer which "encodes" the new values of the chart (that means that the encondeEnd is called again). But, this new "enconding" is not painted in the browser.
The html has two JSF components. My custom component and a h:panelGroup. If in the "update" attribute on primefaces button I put the id of the chart's div and then I trigger the ajax request, the chart does not change. But instead I put the id of the h:panelGroup, the div of the chart disappears.