Visualforce charting is one of the most popular features added to Visualforce while I’ve been writing documentation for the product, and JavaScript Remoting is one of the most powerful. Perhaps you’ve wondered how to combine the two.

Visualforce Pie ChartThis sample shows how to load and update a chart using two different methods, highlighting how to use JavaScript Remoting to smoothly load new data and update the chart. The example chart is a simple pie chart, and updates happen when the user selects a new year to display from a menu.

“Traditional” Visualforce loads the chart data using an expression to call a controller method, and updates the data using an <apex:actionSupport> component to re-render the chart’s section of the page in response to choosing a different year. The technique is well explained in the Visualforce Developer’s Guide.

The JavaScript Remoting version relies on some JavaScript code that I’ve written myself, instead of the automatic behaviors built into Visualforce. It’s a bit more code, but it’s also more flexible, with a smoother transition when the chart is updated. The following sample is more comprehensive than any currently in the Visualforce documentation.

To start with, here’s the controller code, a straightforward expansion of a pie chart controller from the Visualforce Developer’s Guide:

public class PieChartRemoteController {

    // The year to be charted
    public String chartYear {
        get {
            if (chartYear == null) chartYear = '2013';
            return chartYear;
        }
        set;
    }

    // Years available to be charted, for <apex:selectList>
    public static List<SelectOption> getChartYearOptions() {
        List<SelectOption> years = new List<SelectOption>();
        years.add(new SelectOption('2013','2013'));
        years.add(new SelectOption('2012','2012'));
        years.add(new SelectOption('2011','2011'));
        years.add(new SelectOption('2010','2010'));
        return years;
    }

    public List<PieWedgeData> getPieData() {
        // Visualforce expressions can't pass parameters, so get from property
        return PieChartRemoteController.generatePieData(this.chartYear);
    }

    @RemoteAction
    public static List<PieWedgeData> getRemotePieData(String year) {
        // Remoting calls can send parameters with the call
        return PieChartRemoteController.generatePieData(year);
    }

    // Private data "generator"
    private static List<PieWedgeData> generatePieData(String year) {
        List<PieWedgeData> data = new List<PieWedgeData>();
        if(year.equals('2013')) {
            data.add(new PieWedgeData('Jan', 30));
            data.add(new PieWedgeData('Feb', 15));
            data.add(new PieWedgeData('Mar', 10));
            data.add(new PieWedgeData('Apr', 20));
            data.add(new PieWedgeData('May', 20));
            data.add(new PieWedgeData('Jun',  5));
        }
        else {
            data.add(new PieWedgeData('Jan', 20));
            data.add(new PieWedgeData('Feb', 35));
            data.add(new PieWedgeData('Mar', 30));
            data.add(new PieWedgeData('Apr', 40));
            data.add(new PieWedgeData('May',  5));
            data.add(new PieWedgeData('Jun', 10));
        }
        return data;
    }

    // Wrapper class
    public class PieWedgeData {

        public String name { get; set; }
        public Integer data { get; set; }

        public PieWedgeData(String name, Integer data) {
            this.name = name;
            this.data = data;
        }
    }
}

The code is pretty ordinary, except perhaps in that it supports getting chart data via two different methods. getPieData() is intended to be used in a Visualforce expression as {! pieData }, while getRemotePieData() is, as you might guess by the @RemoteAction annotation, intended to be called directly using JavaScript Remoting.

Here’s the Visualforce page, with the two different charts in separate <apex:pageBlockSection>s:

<apex:page controller="PieChartRemoteController">
    <apex:pageBlock title="Charts">

         <apex:pageBlockSection title="Standard Visualforce Charting">

            <apex:outputPanel id="theChart">
            <apex:chart height="350" width="450" data="{!pieData}">
                <apex:pieSeries dataField="data" labelField="name"/>
                <apex:legend position="right"/>
            </apex:chart>
            </apex:outputPanel>

            <apex:form >
                <apex:selectList value="{!chartYear}" size="1">
                    <apex:selectOptions value="{!chartYearOptions}"/>
                    <apex:actionSupport event="onchange" reRender="theChart"
                        status="actionStatusDisplay"/>
                </apex:selectList>
                <apex:actionStatus id="actionStatusDisplay"
                    startText="loading..." stopText=""/>
            </apex:form>

        </apex:pageBlockSection>

        <apex:pageBlockSection title="Visualforce Charting + JavaScript Remoting">

            <apex:chart height="350" width="450" data="retrieveChartData"
                name="RemotingPieChart" hidden="true">
                <apex:pieSeries dataField="data" labelField="name"/>
                <apex:legend position="right"/>
            </apex:chart>

            <div>
                <select id="theYear" onChange="refreshRemoteChart();">
                    <option value="2013">2013</option>
                    <option value="2012">2012</option>
                    <option value="2011">2011</option>
                    <option value="2010">2010</option>
                </select>
                <span id="statusDisplay"></span>
                <span id="remoteResponseErrors"></span>
            </div>

        </apex:pageBlockSection>

    </apex:pageBlock>
</apex:page>

The “normal” Visualforce chart is on lines 4-23, and the Remoting-based chart (well, most of it) is on lines 25-46. You can see that they have similar forms: both <apex:pageBlockSection>s have two blocks of their own, the chart block and the year selection menu form. The two chart blocks are nearly identical, the only meaningful difference is the data attribute for the <apex:chart> tag. The Visualforce chart uses an expression to call a controller method that provides the data. The Remoting chart data attribute is…well, it looks like just a string. I’ll get right back to that. The year selection form for the Visualforce chart uses the expected Visualforce tags, including <apex:actionSupport> to provide the refreshing and <apex:actionStatus> to display a simple “loading” message during a refresh. In contrast, the Remoting version uses static HTML, more to show that you can than because it’s required, and has no apparent way to trigger a refresh.

In the above code sample, the two charts appear to have roughly the same number of lines of code. The thing is, I left off part of the Remoting chart’s code. The JavaScript part of JavaScript Remoting. This part goes between the opening <apex:page> and the <apex:pageBlock> tags:

    <script>
    function retrieveChartData(callback) {
       var year = document.getElementById('theYear').value;
       Visualforce.remoting.Manager.invokeAction(
           '{!$RemoteAction.PieChartRemoteController.getRemotePieData}',
           year,
           function(result, event) {
               if(event.status && result && (result.constructor === Array)) {
                   callback(result);
                   RemotingPieChart.show();
               }
               else if (event.type === 'exception') {
                   document.getElementById("remoteResponseErrors").innerHTML = event.message +
                       '<br/>' + event.where;
               }
               else {
                   document.getElementById("remoteResponseErrors").innerHTML = event.message;
               }                   
           },
           { escape: true }
       );
    }
    function refreshRemoteChart() {
        var statusElement = document.getElementById('statusDisplay');
        statusElement.innerHTML = "loading...";
        retrieveChartData(function(statusElement){
                return function(data){
                    RemotingPieChart.reload(data);
                    statusElement.innerHTML = '';
                };
            }(statusElement)
        );
    }
    </script>

This is the most interesting part of the page, at least for understanding how to combine Visualforce charting and JavaScript Remoting. These two JavaScript functions are the glue between the Visualforce chart and the @RemoteAction controller method that provides the data. There are three links between the functions and the chart component you should notice:

  1. The chart component’s data attribute is the string “retrieveChartData”, which is the name of the first JavaScript function. This tells the chart component to use the JavaScript function to load its data. retrieveChartData() is only invoked once by the chart component directly, when the chart is first created and the data is initially loaded.
  2. Reloading happens when the second JavaScript function, refreshRemoteChart(), is called. This is the second link, and it’s actually from the year menu item, a static HTML element, which has an onChange attribute of refreshRemoteChart();. When you make a change to the menu, refreshRemoteChart() is invoked, and it re-invokes the retrieveChartData() function to load a new set of data.
  3. When refreshRemoteChart() invokes retrieveChartData() it provides an anonymous function as a callback, which handles the result of the @RemoteAction call when it returns. This callback is what actually updates the chart, by calling RemotingPieChart.reload(data). RemotingPieChart is the name I gave to the chart component, on line 29 of the first sample, and reload() is a JavaScript function available on it that accepts new data and then redraws the chart.

Here’s a more visual way to see these links between the different components of the page:

Updating Visualforce Charts with JavaScript Remoting

The sequence for the initial loading of the chart is simple: the <apex:chart> named RemotePieChart calls retrieveChartData() to get its initial data, and retrieveChartData() calls RemotePieChart.show() when it has the data. And, the chart appears.

Updates are more complicated. When a new year is chosen from the theYear menu, the menu’s onChange event fires, which calls refreshRemoteChart(). refreshRemoteChart() in turn calls retrieveChartData(), and when that returns new data, it (via the callback it created) calls RemotePieChart.reload(). And, the chart updates.

The structure of this code sample may seem complicated at first, but it provides a great deal of flexibility in what to display or change at various points in the update cycle. Once you study it a bit, and spend some time writing JavaScript user interface code, you’ll find that it’s perfectly natural.

Here are a couple of other items to note.

  • The <apex:chart> uses the hidden="true" attribute to prevent the chart from displaying before there’s data to display. The retrieveChartData() function calls RemotingPieChart.show() to display the chart once the chart data is loaded. This and RemotingPieChart.reload() provide for much smoother chart animations than what is achieved using <apex:actionSupport>. Add this code into your own org and compare the two.
  • The refreshRemoteData() function sets the statusElement HTML <span> to a “loading…” message before it attempts to update the data by calling retrieveChartData(), and then the anonymous callback function sets it to an empty string to hide the message once the data is returned and the chart updated. It’s a bit more work than using <apex:actionStatus> for basically the same effect. You could easily show a “busy” animation or graphic using the same technique.

This article was inspired by a recent post in the Visualforce discussion forum, which asked about using JavaScript Remoting to load and update chart data, and how to get the chart to draw with that data. We answered the question in the discussion, but I wanted to also expand the existing documentation on the topic. The code sample in this article, and the explanation (in substantially different form), will appear in a future edition of the Visualforce Developer’s Guide. I hope it’s useful, and interesting, to get a preview of that documentation a little early.

tagged , , Bookmark the permalink. Trackbacks are closed, but you can post a comment.
  • Rich

    No doubt remoting has it’s benefits. It seems to be the trend for developers to use it at every opportunity (no pun intended). Imho, having used javascript remoting I don’t find it as flexible as the traditional way. If you ever have to use other variables (class properties) in your controller method then you are out of luck. There is a workaround, meaning you have to pass everything in parmeters back and forth. You may think you don’t need to use class properties, but maybe later something is changed where you do need to incorporate them and then it becomes more messy. Or you may end up re-coding back to the traditional model. Would like to know if there is a “clean” way to do remoting for this scenario, even if it just means it is more readable (design pattern?). For now, I would put a “use with caution” label on it though. I have had disputes with colleagues who insist it being used, so be wary.

  • Raj Chilukuri

    Very informative. Thank you.

  • Rammy Kumar

    Just wondering can we include an click events to chart to extract data set values and use it some where else ??