Search code examples
ruby-on-railshighchartschartkick

Chartkick on rails: change the graph style based on the data


I'm using chartkick highchart to shows some graph in rails application. My question is can the style of chartkick graph be changed based on data provided by the chart controller?

for example this is the code in the chart.html.erb:

<%= line_chart charts_cards_history_by_day_path, refresh: 10 %>

is there a way to change that code to <%= bar_chart charts_cards_history_by_day_path, refresh: 10 %> based on the decision made by the chart controller? So it is up to the controller whether the chart style is line or bar chart.

Thanks, Randy

the controller source:

def cards_history_by_day

      begin

        p_board_id = params['post']['board_id']

        render json:
          [{name: "No. of cards", data: ListsCountPerday.joins(:t_list).where('lists_count_perdays.t_board_id = '+p_board_id+' and
            t_lists.t_list_type_id != 1').group(:date).pluck('date, sum(count)')},
          {name: "Completed", data: ListsCountPerday.joins(:t_list).where('lists_count_perdays.t_board_id = '+p_board_id+' and
            t_lists.t_list_type_id = 5').group(:date).pluck('date, sum(count)')}]

      rescue
        render json: CardHistory.where('t_list_id = -1').group_by_day(:created_at).count
      end

  end

The view source:

# javascript to handle selection and form submission
<%= javascript_include_tag "charts0" %>

# form for user select prefered data to show
<%= form_tag charts0_cards_history_by_day_path , remote: true do %>
<label for="team_name">Team: </label>
<%= collection_select "post", "authentication_id",
            Authentication.order(:team_name), :id, :team_name, prompt: "Please select"  %>
<label for="team_name">Board: </label>
 <%= grouped_collection_select "post", "board_id",
            Authentication.order(:team_name), :t_board, :team_name, :id, :name, prompt: "Please select" %>
 <%= submit_tag 'Apply', class: 'btn btn-primary' %>
<% end %>

#function to show the chart which data taken from the controller
<%= line_chart charts0_cards_history_by_day_path, refresh:10 %>

The javascript source:

#javascript to update chart data once form is submitted
$(document).ready(function() {
  $('form').submit(function(e) {
    e.preventDefault();
    data = $(this).serialize();

    Chartkick.eachChart( function(chart) {
      chart.updateData(chart.getDataSource() + '?' + data);
    });

    return false;
  });
});

Updated controller source (returned an uninitialized constant error for Chart.last.data at cards_history_by_day.js.erb):

def cards_history_by_day

          begin

            p_board_id = params['post']['board_id']

           #call the .js.erb file (based on the JS tutorial given)
           respond_to do |format|
             format.js
           end

          rescue
            render json: CardHistory.where('t_list_id = -1').group_by_day(:created_at).count
          end

      end

Solution

  • Many Thanks to @Kartikey Tanna who inspired me to answer the question. As mentioned, yes I need to modify @Kartikey Tanna a little bit to make things work.

    So in addition to @Kartikey Tanna solution. First, I create a new controller method named setChartsData and leave the cards_history_by_day method as the original (render json):

    def setChartsData
          begin
            # get post data once the form is submitted
            p_board_id = params['form']['board_id']
            # set global variable to store board id
            @formbid = p_board_id
            # set global variable as decider which chart style will be shown
            @dataCountPd = ListsCountPerday.group(:date).count.count
    
            respond_to do |format|
              format.js
            end
        rescue
          # do nothing
        end
      end 
    

    Second, I create setChartsData.js.erb with only to render a partial to an empty div id in the view file:

    $("#charts_div").html("<%= j render(partial: 'chart') %>");
    

    Third, I modify my view file from <%= line_chart charts0_cards_history_by_day_path, refresh:10 %> into an empty div like this:

    <div id="charts_div" class="tab-content">
      <div id="chart_perdays" class="tab-pane fade in active"></div>
    </div>
    

    Finally, I create the partial like this:

    <div id="chart_perdays" class="tab-pane fade in active">
      <% if @dataCountPd == 1 %>
          <%= bar_chart charts0_cards_history_by_day_path(bid:@formbid), refresh:10 %>
      <% elsif @dataCountPd > 1 %>
          <%= line_chart charts0_cards_history_by_day_path(bid:@formbid), refresh:10 %>
      <% end %>
    </div>
    

    You can see, if the @dataCountPd from the controller method return 1, a bar chart will be shown, else a line chart will be shown. Also, after the bar_chart/line_chart command, there is a controller method to returns data for the graph, this time I add a parameter bid for query reason in the method.

    Best, Randy