0

I have a Rails application and I want to use Google Charts on a page. So in the view I load the javascript file (which contains the Google Charts code) to show the graph:

content_for(:head) do
  = javascript_include_tag 'infograph'

#chart_div{"data-hours" => @billable_hours }

This all works nicely, the graph is shown. However, I have a variable ``@hours```I want to pass to the javascript file, because it contains the graph data. How can I do that?

I read about using a data label like #chart_div{"data-hours" => @billable_hours }, but I don't know how to use that in the Javascript file. Using alert(data('hours')); doesnn't seem to work. How can I do this? Thanks!

1 Answer 1

1

Initial data

Using data attributes is the correct way to initialize data in javascript : data is attached to DOM elements when you render the page, so javascript can access it when it is executed, on DOMReady.

Vanilla javascript

With plain javascript, you would have to retrieve it on dom element :

document.querySelect('#chart_div').getAttribute('data-hours')

Beware that it will always be a string (or undefined if attribute does not exist), so you have to do your typecasts yourself if you want to have anything else :

var myInt = parseInt(document.querySelect('#chart_div').getAttribute('data-hours'), 10)

jQuery

If you use jQuery, you can retrieve your data using .data() :

$('#chart_div').data('hours')

This will do type conversion for you and provide a quite simpler interface to access data attributes.

Be aware, though, that this is for initial data. If you change the value of data-hours after data container has already been initialized, it won't be reflected. So with the following html :

<div id="chart" data-hours="10"></div>

This will happen after DOMReady :

# data() is correctly initialized
$('#chart').data('hours') # => 10

# changing attribute does not reflect in data container
$('#chart').attr('data-hours', 7)
$('#chart').attr('data-hours') # => 7
$('#chart').data('hours') # => 10

# changing data container does not reflect in attribute
$('#chart').data('hours', 5)
$('#chart').data('hours') # => 5
$('#chart').attr('data-hours') # => 7

The thing to remember here is that jQuery's .data() method actually handles a separated container, which defaults are initialized from data-* attributes from dom element.

If you want to retrieve data from an element which initial data-* attribute has been changed, you have to use .attr() (and do typecast yourself).

Big or asynchronous data

If you begin to have a lot of data to pass, you should avoid using data attributes : I does not make sense to have a html page which data attributes count for the half or third of the page.

In that case, you should defer your js initialization and request for data through ajax. This is also how you pass data after page has already been initialized.

For example, if you're on a index page that loads a few Items on page initial load, then loads a huge collection of them through async javascript, you could do something like that, in your controller :

class ItemsController < ApplicationController
  def index
    respond_to do |format|
      format.html { @items = Item.all.limit(5) }
      format.json { render json: { items: Item.all.limit(1000) } }
    end
  end
end

With jQuery, you can use $.getJSON to retrieve your large collection :

$.getJSON( '/items', function(items){ console.log(items) });

You now can use your data in place of that console.log, with all common types (integer, float, array, object/hash, string) already casted as expected.

PS

Oh, by the way :

#chart_div{"data-hours" => @billable_hours }

There is a dedicated syntax for that :

#chart_div{ data: { hours: @billable_hours } }

It's especially useful as a shorthand when you have three of four data attributes.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.