In this section, we'll use AJAX in Ruby on Rails and generate dynamic charts. We'll do the following:

  • Create a page which will contain a drop-down of Factory names and the details of that factory in a Column chart.
  • On selecting a factory from the drop-down, the chart updates to show the details of the selected factory.

Before you proceed with the contents in this page, we recommend you to go through the section "Basic Examples ".

All code discussed here is present in
Controller : Download Package > Code > RoR > SampleApp > app > fusioncharts > controllers > ajax_example_controller.rb.
View : Download Package > Code > RoR > SampleApp > app > views > fusioncharts > ajax_example folder.
View Helper Modules: Download Package > Code > RoR > SampleApp > lib > fusion_charts_helper.rb

Creating the page with factory names drop-down and initial chart.

We will create a controller called AjaxExampleController with the action default_factory_form for this page.

The code in the controller and view are given below.

Controller: Fusioncharts::AjaxExampleController
Action: default_factory_form
class Fusioncharts::AjaxExampleController < ApplicationController
    def default_factory_form
        response.content_type = Mime::HTML
        @factories = Fusioncharts::FactoryMaster.find(:all)
        if(@factories.size>0)
            factory = @factories[0]
            @factory_id = factory.id # Default factory
            factory = Fusioncharts::FactoryMaster.find(@factory_id)
            @factory_name = factory.name
            @factory_output_quantities = factory.factory_output_quantities
        end
end
end

View: default_factory_form.html.erb
<HTML>
<HEAD>
<TITLE>FusionCharts - Ajax Based Data Charting Example</TITLE>
<%= javascript_include_tag "FusionCharts" %>
<%= javascript_include_tag 'prototype' %>
<style type="text/css">
<!--
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
}
.text{
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
}
-->
</style>
<SCRIPT LANGUAGE="JavaScript">
/*updateChart method is invoked when response for the factory_json action is obtained.
In this method, we build the XML data
for the selected factory, using data stored in JSON, and finally
update the Column Chart.
@param request
*/
function updateChart(request){
if (request.readyState == 4 /*complete*/) {

var output_quantities = eval('(' + request.responseText + ')');
var index = document.getElementById("factory_factory_id").selectedIndex;
var selected_factory = document.getElementById("factory_factory_id").options[index].text;
var strXML = "<chart palette='2' caption='" + selected_factory + " Output ' subcaption='(In Units)' xAxisName='Date' showValues='1' labelStep='2' >";
for(i=0;i<output_quantities.size();i++){
strXML = strXML + "<set label='" + output_quantities[i].formatted_date+ "' value='" + output_quantities[i].quantity + "' />";
}
//Closing Chart Element
strXML = strXML + "</chart>";
}
//Get reference to chart object using Dom ID "AjaxChart"
var chartObj = getChartFromId("AjaxChart");
//Update it's XML
chartObj.setDataXML(strXML);
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<h2>FusionCharts Ajax And JSON Example</h2>
<p class='text'>Select a factory to view its details</p>
<table width='50%' align='center' cellpadding='2' cellspacing='1'
border='0' class='text'>
<tr>
<td align='center'><B>Select Factory:</B>

<%= collection_select("factory", "factory_id", @factories, :id, :name,{},{:onChange=>remote_function(:url=>{:action=>'factory_json'},:with => "'factory_id='+value", :complete=>'javascript:updateChart(request)')} )%>
</td>
</tr>
<tr>
<td colspan=2>
<%= render :partial=>"factory_details_chart", :locals=>{:factory_id=> @factory_id,:factory_name=>@factory_name,:factory_output => @factory_output_quantities} %>
</td>
</tr>
<table>
</CENTER>
</BODY>
</HTML>

The following steps are carried out in the controller action:

  1. Find all the factories present in the database. This data is stored in @factories, which is used in the view to showa drop-down of factory names.
  2. The first factory is taken as default factory. The factory name and output quantities for this factory are stored in @factory_name and @factory_output_quantities. These values are used in the view, to show the chart.

Let us next, dissect the view page and see it part by part. To show the drop-down of factory names, we will use the collection_select helper method. This is shown below:

<%= collection_select("factory", "factory_id", @factories, :id, :name,{},{:onChange=>remote_function(:url=>{:action=>'factory_json'},:with => "'factory_id='+value", :complete=>'javascript:updateChart(request)')} )%>

We have added onChange handler to this drop-down. When the user selects a different factory from this drop-down, it contacts the action factory_json from the same controller with factory_id as parameter. On completing the action, the javascript function updateChart will be invoked.

In order to show the chart, we will render a partial _factory_details_chart passing it the factory id, name and output quantities. The partial renders the chart using FusionChartsHelper and the factory_details builder file. Here we will not go into the details of the partial and the builder, since they are similar those seen in Drill Down example and other examples.The resulting chart is shown below:

On selecting a different factory from the drop-down, the chart with that factory's details should be shown. For this, we will use AJAX. Since Ruby on Rails provides great support for AJAX, our task is very simple. As seen in the above code, we have provided the :url, :with and :complete parameters to the remote_function which is given to the onChange handler. The url provided to the remote_function is :action=> 'factory_json'. Let us analyze the action and its output. The code for this action is:

Controller: Fusioncharts::AjaxExampleController
Action: factory_json

    def factory_json
       factory_id = params[:factory_id]
       factory = Fusioncharts::FactoryMaster.find(@factory_id)
       factory_output_quantities = factory.factory_output_quantities
       response.content_type = Mime::JSON
       render :json=>factory_output_quantities.to_json(:methods=>'formatted_date')
    end

In this action, the expected parameter is factory_id. A look-up is performed and the factory details for this id is obtained. The factory_output_quantities of the factory is converted to JSON format using the to_json method. Note that, we have used :methods=>'formatted_date'. This means the formatted_date method from FactoryOutputQuantity model class will be included in the resulting JSON, then the view can directly use this value instead of the unformatted date obtained from database. This json is then rendered. The action is complete.

On completing the action, the javascript function updateChart is called. It receives the Factory details in the JSON format. Let us focus on this javascript function now.

function updateChart(request){
if (request.readyState == 4 /*complete*/) {

var output_quantities = eval('(' + request.responseText + ')');
var index = document.getElementById("factory_factory_id").selectedIndex;
var selected_factory = document.getElementById("factory_factory_id").options[index].text;
var strXML = "<chart palette='2' caption='" + selected_factory + " Output ' subcaption='(In Units)' xAxisName='Date' showValues='1' labelStep='2' >";
for(i=0;i<output_quantities.size();i++){
strXML = strXML + "<set label='" + output_quantities[i].formatted_date+ "' value='" + output_quantities[i].quantity + "' />";
}
//Closing Chart Element
strXML = strXML + "</chart>";
}
//Get reference to chart object using Dom ID "AjaxChart"
var chartObj = getChartFromId("AjaxChart");
//Update it's XML
chartObj.setDataXML(strXML);
}

In this function, the following steps are performed:

  1. Check if the request is in ready state. If request is ready, the responseText is taken from the request.
  2. Create the xml for the chart for the selected factory. Top-most element is the chart tag.
  3. Create set tag for each element in the responseText (output_quantitiess). Assign label as output_quantities[i].formatted_date and value as output_quantities[i].quantity.
  4. Close the chart tag.
  5. Use getChartFromId to obtain handle to the chart object, passing the chartId "AjaxChart" as parameter.
  6. Invoke the setDataXML on the chart object with the XML created in the previous steps.

Our job is done. The chart will now get refreshed with details of the selected factory.

In this example, we have seen

  • how to use AJAX to trigger an action whenever the user selects a name from the drop-down
  • how an action can respond with JSON
  • how a Javascript callback function can parse the JSON output and create XML
  • finally, how to display the chart with new details.

This is just the beginning of what can be achieved with Ruby on Rails, AJAX and FusionCharts. Keep exploring!