function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
nickwick76nickwick76 

Loading Visualforce charts with RemoteAction

Hi,

My goal is to call a controller from a visualforce component using Javascript remoting and then to update the visualforce chart with the result.

 

The javascript remoting call works fine and I can see in the debug console that it receives the correct values as well. But how do I update the chart with this data?

 

Here's the javascript code. testCharts is my controller and getRemoteData is the RemoteAction method.

 

<script type="text/javascript">
function getOppChart() {
var year = '2013';

Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.testCharts.getRemoteData}',
year,
function(result, event) {
if (event.status) {
	// Actions here, update VF chart?
} else if (event.type === 'exception') {
	document.getElementById("responseErrors").innerHTML = event.message;
} else {
	document.getElementById("responseErrors").innerHTML = event.message;
}
}, 
{escape: true}
);
}
</script>

The visualforce chart component. The data attribute is required. How do I pass the result from the javascript function here? I would like to make this dynamic so that when I select a value in a picklist on the page a new call is made and the chart is refreshed. But as a start I'd just like to know how to get the result there. If I was just using a controller I would just put the method name in the data attribute, i.e. data="{!oppData}".

 

<apex:chart height="300" width="600" data="???">
	<apex:axis type="Numeric" position="left" fields="data,data2" 
	title="Total Order value" grid="true"/>
	<apex:axis type="Category" position="bottom" fields="name" 
	title="Month of the Year">
	</apex:axis>
	<apex:lineSeries axis="left" fill="true" xField="name" yField="data2"
	markerType="cross" markerSize="4" markerFill="#FF0000"/>
</apex:chart>

 The reason I am not using the Apex controller methods directly is because of three reasons.

- I hope the user will find this more reponsive

- I want to be able to rerender the charts

- I just want to make it work!!!

 

Can't find anything on the boards or google. Anyone got ideas?? Much appreciated!

 

Thanks / Niklas

 

Best Answer chosen by Admin (Salesforce Developers) 
nickwick76nickwick76

I managed to solve this myself.

 

See below additions to the code that made it work.

 

<script type="text/javascript">
function getOppChart(callback) {
var year = document.getElementById('yearId').value;

Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.testCharts.getRemoteData}',
year,
function(result, event) {
if (event.status) {
	callback(result);
} else if (event.type === 'exception') {
	document.getElementById("responseErrors").innerHTML = event.message;
} else {
	document.getElementById("responseErrors").innerHTML = event.message;
}
}, 
{escape: true}
);
}
</script>

 Just use the javascript method name in the data attribute

<apex:chart height="300" width="600" data="getOppChart">
	<apex:axis type="Numeric" position="left" fields="data,data2" 
	title="Total Order value" grid="true"/>
	<apex:axis type="Category" position="bottom" fields="name" 
	title="Month of the Year">
	</apex:axis>
	<apex:lineSeries axis="left" fill="true" xField="name" yField="data2"
	markerType="cross" markerSize="4" markerFill="#FF0000"/>
</apex:chart>

 This way you can have a select list with values (in this example it has the id 'yearId'). When you select a new value in the picklist it rerenders (using actionSupport) an outputpanel which includes the chart component. The chart will be reloaded with a new javascript call using the newly selected argument (year).

 

The controller code is the same as in the examples you can find in Salesforce docs.

 

// Niklas

 

All Answers

nickwick76nickwick76

I managed to solve this myself.

 

See below additions to the code that made it work.

 

<script type="text/javascript">
function getOppChart(callback) {
var year = document.getElementById('yearId').value;

Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.testCharts.getRemoteData}',
year,
function(result, event) {
if (event.status) {
	callback(result);
} else if (event.type === 'exception') {
	document.getElementById("responseErrors").innerHTML = event.message;
} else {
	document.getElementById("responseErrors").innerHTML = event.message;
}
}, 
{escape: true}
);
}
</script>

 Just use the javascript method name in the data attribute

<apex:chart height="300" width="600" data="getOppChart">
	<apex:axis type="Numeric" position="left" fields="data,data2" 
	title="Total Order value" grid="true"/>
	<apex:axis type="Category" position="bottom" fields="name" 
	title="Month of the Year">
	</apex:axis>
	<apex:lineSeries axis="left" fill="true" xField="name" yField="data2"
	markerType="cross" markerSize="4" markerFill="#FF0000"/>
</apex:chart>

 This way you can have a select list with values (in this example it has the id 'yearId'). When you select a new value in the picklist it rerenders (using actionSupport) an outputpanel which includes the chart component. The chart will be reloaded with a new javascript call using the newly selected argument (year).

 

The controller code is the same as in the examples you can find in Salesforce docs.

 

// Niklas

 

This was selected as the best answer
cwall_sfdccwall_sfdc

Glad you found the solution.  Your source is a great example of using a JS function and VF remoting to load chart data.

 

From VF Dev Guide:

 

apex:chart.data&colon;

"Specifies the data binding for the chart. This can be a controller method reference in an expression, a JavaScript function, or a JavaScript object. In all cases, the result must be an array of records, and every record must contain all fields referenced in child data series components."

Alderete_SFDCAlderete_SFDC

FWIW, there's also a code sample in the Visualforce Developer's Guide that illustrates this, in the charting chapter under "Providing Chart Data Using a JavaScript Function":

 

http://www.salesforce.com/us/developer/docs/pages/index_Left.htm#StartTopic=Content/pages_charting_overview.htm

 

<apex:page>
    <script>
    function getRemoteData(callback) {
       PieChartController.getRemotePieData(function(result, event) {
           if(event.status && result && result.constructor === Array) {
               callback(result);
           }
       });
    }
    </script>

    <apex:chart data="getRemoteData" ...></apex:chart>
</apex:page>

 

What may have thrown you off is that this sample uses the terse way of calling a remote method and other shortcuts, and that makes it less obvious what's actually going on, or that it's using JavaScript Remoting at all.

 

Being so terse is not great doc, so I'm guilty here. I'm taking it as an action item to expand the sample, so that it's more clear how to work with Remoting.

nickwick76nickwick76

Thanks! I think it would be really good if you could do that!

A suggestion is to explain more about the callback function as well which can be perceived as magic when you first run into it.

Alderete_SFDCAlderete_SFDC

Just to close this loop, I have updated the Visualforce Developer's Guide with a substantially expanded version of the code from the doc mentioned above. But since I'm working on the next release, those docs won't be published for another three months. So I have also published a somewhat different version of the code in a blog post on developer.force.com:

 

Refreshing Visualforce Charts with Updated Data

 

Let me know if you think the supplied code sample and explanations cover the original question, as well as @nickwick76's suggestion to explain how the callback works. (I don't explain callback fundamentals, that's basic computer science, but I do try to explain how they're used in the context of JavaScript Remoting.)

 

Cheers!

geeta garggeeta garg
Hi,

On changing of the picklist, chart data is modified but maximum value is not modified. How can we refresh the maximum value of the chart?

Thanks,