I'm trying to create a collapsing/expanding animated treeview in
Javascript. I found the JQuery treeview plugin, and it's working
great. However, I have one key need that I can seem to figure out
with the samples provided:
Basically I need the "advanced async feature" they provide (http://
jquery.bassistance.de/treeview/demo/async.html). As the user clicks
on each "main node" in the tree, I need to make an AJAX-call to pull
in the sub-tree links. My problem is that I need to do some post-
processing in JS of the JSON data that comes back from the server in
order to keep the tree-view plugin happy (and I don't control the
API's on the server for the data-source)
When I make my call to the API to retrieve it top-level tree, the JSON
data comes back like this:
navcallback({"response":{"statusCode":200,"data":{"genrelist":{"genre":
[{"id":1,"haschildren":true,"name":"Alternative","parentid":0},{"id":
24,"haschildren":true,"name":"Blues","parentid":0},{"id":
32,"haschildren":true,"name":"Classical","parentid":0},{"id":
44,"haschildren":true,"name":"Country","parentid":0},{"id":
212,"haschildren":true,"name":"Decades","parentid":0},{"id":
54,"haschildren":true,"name":"Easy Listening","parentid":0},{"id":
61,"haschildren":true,"name":"Electronic","parentid":0},{"id":
82,"haschildren":true,"name":"Folk","parentid":0},{"id":
122,"haschildren":true,"name":"Inspirational","parentid":0},{"id":
134,"haschildren":true,"name":"International","parentid":0},{"id":
163,"haschildren":true,"name":"Jazz","parentid":0},{"id":
177,"haschildren":true,"name":"Latin","parentid":0},{"id":
195,"haschildren":true,"name":"Metal","parentid":0},{"id":
295,"haschildren":false,"name":"Misc","parentid":0},{"id":
206,"haschildren":true,"name":"New Age","parentid":0},{"id":
220,"haschildren":true,"name":"Pop","parentid":0},{"id":
232,"haschildren":true,"name":"R&B/Urban","parentid":0},{"id":
110,"haschildren":true,"name":"Rap","parentid":0},{"id":
242,"haschildren":true,"name":"Reggae","parentid":0},{"id":
250,"haschildren":true,"name":"Rock","parentid":0},{"id":
265,"haschildren":true,"name":"Seasonal/Holiday","parentid":0},{"id":
276,"haschildren":true,"name":"Soundtracks","parentid":0},{"id":
282,"haschildren":true,"name":"Talk","parentid":0},{"id":
89,"haschildren":true,"name":"Themes","parentid":
0}]}},"statusText":"Ok"}});
All is well, but I need to do some JS processing on it as it comes
back, so I run it through a script like this:
function navcallback(d) {
var response='[';
for (i=0;i<=d.response.data.genrelist.genre.length - 1;i++) {
response += '{"text": "'+d.response.data.genrelist.genre[i].name
+'","id": "'+d.response.data.genrelist.genre[i].id+'","hasChildren":
true},';
}
response = response.slice(0, -1);
response += ']';
}
Which then gets the data in the format that jQuery treeview expects
it:
[{"text": "Alternative","id": "1","hasChildren": true},{"text":
"Blues","id": "24","hasChildren": true},{"text": "Classical","id":
"32","hasChildren": true},{"text": "Country","id": "44","hasChildren":
true},{"text": "Decades","id": "212","hasChildren": true},{"text":
"Easy Listening","id": "54","hasChildren": true},{"text":
"Electronic","id": "61","hasChildren": true},{"text": "Folk","id":
"82","hasChildren": true},{"text": "Inspirational","id":
"122","hasChildren": true},{"text": "International","id":
"134","hasChildren": true},{"text": "Jazz","id": "163","hasChildren":
true},{"text": "Latin","id": "177","hasChildren": true},{"text":
"Metal","id": "195","hasChildren": true},{"text": "Misc","id":
"295","hasChildren": true},{"text": "New Age","id":
"206","hasChildren": true},{"text": "Pop","id": "220","hasChildren":
true},{"text": "R&B/Urban","id": "232","hasChildren": true},{"text":
"Rap","id": "110","hasChildren": true},{"text": "Reggae","id":
"242","hasChildren": true},{"text": "Rock","id": "250","hasChildren":
true},{"text": "Seasonal/Holiday","id": "265","hasChildren": true},
{"text": "Soundtracks","id": "276","hasChildren": true},{"text":
"Talk","id": "282","hasChildren": true},{"text": "Themes","id":
"89","hasChildren": true}]
However, I can't for the life of me figure out how to get this
integrated with the JQuery treeview's async.js code (below). All
would be fine if I didn't need to do this post-processing, but I need
to.
Gotcha's that I'm dealing with:
1) The API data is coming from a cross-domain server, so I think I
probably need to use the $.getScript call to retrieve the JSONp data.
2) I can't figure out how to get my navback handler integrated into
the "load" function of treeview. If I insert my "response-
reformatting code" inside the getJSON function, all kinds of bad
things start happening. I suspect it has to do with the "this"
objects and parent and other things which are quite complex in this
plugin.
function load(settings, root, child, container) {
$.getJSON(settings.url, {root: root}, function(response) {
function createNode(parent) {
mythis = this;
var current = $("<li/>").attr("id", this.id ||
"").html("<span>" +
this.text + "</span>").appendTo(parent);
if (this.classes) {
current.children("span").addClass(this.classes);
}
if (this.expanded) {
current.addClass("open");
}
if (this.hasChildren || this.children &&
this.children.length) {
var branch = $("<ul/>").appendTo(current);
if (this.hasChildren) {
current.addClass("hasChildren");
createNode.call({
text:"placeholder",
id:"placeholder",
children:[]
}, branch);
}
if (this.children && this.children.length) {
$.each(this.children, createNode,
[branch])
}
}
}
$.each(response, createNode, [child]);
$(container).treeview({add: child});
});
}
var proxied = $.fn.treeview;
$.fn.treeview = function(settings) {
if (!settings.url) {
return proxied.apply(this, arguments);
}
var container = this;
load(settings, "source", this, container);
var userToggle = settings.toggle;
return proxied.call(this, $.extend({}, settings, {
collapsed: true,
toggle: function() {
var $this = $(this);
if ($this.hasClass("hasChildren")) {
var childList =
$this.removeClass("hasChildren").find("ul");
childList.empty();
load(settings, this.id, childList, container);
}
if (userToggle) {
userToggle.apply(this, arguments);
}
}
}));
};
})(jQuery);