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.