I'm trying to generate a collapsible force layout similar to this example: http://bl.ocks.org/mbostock/1062288:

The data being used to generate my force layout is a JSON object being sourced from an API. I am successfully able to traverse the data structure, and generate nodes that are appended to the SVG (both root nodes and their children).
However, the issue comes with linking the parent nodes to their children nodes. Links are not being generated, and my links variable is returning an empty array. I'm pretty sure that the issue has something to do with how the data is structured in my app compared to the example, so I'll post both my JS code and the data structure of each node.
Any help would be much appreciated! Thanks in advance!!
Here's a JS Fiddle with my code: http://jsfiddle.net/tmzjW/
Here is my JS code:
//Force Layout Code
var w = 607,
h = 500,
node,
link,
root;
var force = d3.layout.force()
.on("tick", tick)
.size([w, h]);
var vis = d3.select("#chart").append("svg:svg")
.attr("width", w)
.attr("height", h);
function initiateForceJS(currentURL) {
//Generate the URL
forceURL = currentURL + ".json?jsonp=?";
$('#commentArea').show();
$.getJSON(forceURL,handleRequest2);
function handleRequest2(json) {
//Set the root as the first object returned
root = json[1]['data']['children'][0];
update();
}
}
function update() {
nodes = flatten(root),
links = d3.layout.tree()
.sort(null)
.children(function(d) {return (!d['replies']['data']['children']|| d['replies']['data']['children'].length === 0) ? null : d['replies']['data']['children'];})
.links(nodes);
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.start();
// Update the links…
link = vis.selectAll("line.link")
.data(links, function(d) { return d.target.id; });
// Enter any new links.
link.enter().insert("svg:line", ".node")
.attr("class", "link")
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
// Exit any old links.
link.exit().remove();
// Update the nodes…
node = vis.selectAll("circle.node")
.data(nodes, function(d) {return d.id; })
.style("fill", color);
// Enter any new nodes.
node.enter().append("svg:circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return Math.sqrt(d.ups) || 4.5; })
.style("fill", color)
//.on("click", click)
.call(force.drag);
// Exit any old nodes.
node.exit().remove();
//This will add the name of the character to the node
node.append("comment").text(function(d) { return d.body });
//This will put the comment in the Comment Area div
node.on("mouseover", function() {
var currentNode = d3.select(this);
var currentTitle = currentNode.select("comment").text();
$('#commentArea').html('<p>' + currentTitle + '</p>')
});
}
function tick() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
// Color leaf nodes orange, and packages white or blue.
function color(d) {
return d._children ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
}
// Returns a list of all nodes under the root.
function flatten(root) {
var nodes = [], i = 0;
function recurse(node) {
if (node['data']['replies'] != "" && node['kind'] != "more") {
node['data']['replies']['data']['children'].forEach(recurse);
}
if (node['kind'] !="more") {
//Add an ID value to the node starting at 1
node.data.id = ++i;
var comment = node.data;
nodes.push(comment);
}
}
recurse(root);
return nodes;
}