I'm trying to use the chronoline.js timeline to display events in my Rails app. The format expected by chronoline is:
var events = [
{dates: [new Date(2015, 1, 29)], title: "First Event"},
{dates: [new Date(2015, 3, 9), new Date(2015, 3, 11)], title: "Second Event"}
];
The dates node is an array of one or two dates, depending on whether the event spans multiple days. I'm trying to generate this using RABL or JBuilder but I don't understand either how to create the array or append "new Date".
I'm new to this. I ended up trying to concatenate it all within a RABL view:
collection @events
attributes :title
node :dates do |d|
if d.end.nil? then
"[new Date(" + d.start.to_s + ")]"
else
"[new Date(" + d.start.to_s + "), new Date(" + d.end.to_s + ")]"
end
end
....but that doesn't work because it outputs the entire array statement as a string in quotes. But doing it like this doesn't feel right anyway.
How do I get RABL (or JBuilder) to assemble the array?
You can't achieve this in the JSON response from Rabl or jBuilder, because Chronoline is expecting JavaScript date objects.
To do this, I recommend the following:
1) Load the json you want into your view in a data-attribute:
<%= content_tag :div, "", id: "mytimeline", data: { events: timeline_json(@events) } %>
2) Use a helper method to construct your JSON, with Dates in a format that can easily be parsed with MomentJS:
def timeline_json(events)
events.map { |event| { start: event.start.strftime("%F %T"), end: event.end.strftime("%F %T"), title: event.title } }.to_json
end
3) Install the momentjs-rails gem, and make sure it's loaded in your asset pipeline. We'll use this for parsing the JSON dates, to easily convert them into Javascript date objects.
4) Use map in JavaScript, to recast the date objects when you instantiate Chronoline.
function drawChronoline() {
// Load the Raw JSON data:
var raw_data = $("#mytimeline").data('events');
// Loop over the JSON, and map it into the format required by Chronoline. Here's a simple example to get you started:
var events = raw_data.map(function(event){
return { dates: [moment(event.start).toDate(), (!event.end ? null : moment(event.end).toDate())], title: event.title }
});
// Instantiate chronoline, with your mapped data:
var timeline = new Chronoline($("#mytimeline"), events);
}
If you would prefer an asynchronous approach that uses RABL to load your events (rather than using a Helper and a Data-attribute), you can easily do that with:
var raw_data = $.get("/events.json");
And your RABL would simply look like:
collection @events
attributes :title
node(:start) { |event| event.start.strftime("%F %T") }
node(:end) { |event| event.end ? event.end.strftime("%F %T") : "" }