In many cases, you'll want to avoid rendering your TreeView Control with a full dataset. Rather, you'll want to load all visible nodes immediately and then retrieve data only when needed for nodes that aren't visible when the control is first loaded. This example shows you how to do that.
In the TreeView instance below, we've loaded all "top-level" nodes into the page as soon as the page loads; these nodes contain the names of several popular music groups. When a node is expanded, we use Connection Manager to access a Yahoo! Music web service that will return a list of tracks from the group that you can listen to. So when the page loads, we know nothing about our top-level nodes' children. And while the resulting TreeView instance could grow quite large through user interaction, we need only load a very light set of nodes to begin with.
Dynamic loading of a TreeView Control's
child nodes allows you to optmize
performance by only loading data for and creating the nodes that will
be visible when the tree is rendered. Nodes that are not expanded when
the TreeView's draw
method is invoked are left childless in the initial
state. When such a node is expanded (either by user action or by
script), a dynamic loader function is called. That function has three
important roles:
Here's how the code on this page manages those three steps. First, we markup the page with a target element into which the TreeView's DOM structure will be injected:
1 | <div id="treeDiv1"></div> |
view plain | print | ? |
Next, we build a function that creates our initial TreeView:
1 | function init() { |
2 | //create a new tree: |
3 | tree = new YAHOO.widget.TreeView("treeDiv1"); |
4 | |
5 | //turn dynamic loading on for entire tree: |
6 | tree.setDynamicLoad(loadNodeData, currentIconMode); |
7 | |
8 | //get root node for tree: |
9 | var root = tree.getRoot(); |
10 | |
11 | //add child nodes for tree; our top level nodes are bands |
12 | var bands = ["Radiohead","Phoenix","Bon Iver","Born Ruffians","LCD Soundsystem","Blind Pilot","The Black Keys"]; |
13 | |
14 | for (var i=0, j=bands.length; i<j; i++) { |
15 | var tempNode = new YAHOO.widget.TextNode(bands[i], root, false); |
16 | } |
17 | |
18 | //render tree with these toplevel nodes; all descendants of these nodes |
19 | //will be generated as needed by the dynamic loader. |
20 | tree.draw(); |
21 | } |
view plain | print | ? |
We have turned on dynamic loading (in line 6 above) at the TreeView level rather than on a specific node, so every expanding node now will invoke our dynamic load handler (loadNodeData
). That means that before the node expands, the node object will be passed to loadNodeData
along with a callback function and the expansion won't take place until we fire that callback. That gives us a chance to load child nodes before the expand action occurs.
We'll use Connection Manager to get external data. Here's our loadNodeData
function, with comments describing what happens at each step.
1 | function loadNodeData(node, fnLoadComplete) { |
2 | //We'll load node data based on what we get back when we |
3 | //use Connection Manager topass the text label of the |
4 | //expanding node to the Yahoo! |
5 | //Music track search API. Here, we're at the |
6 | //first part of the request -- we'll make the request to the |
7 | //server. In our success handler, we'll build our new children |
8 | //and then return fnLoadComplete back to the tree. |
9 | |
10 | //Get the node's label and urlencode it; this is the word/s |
11 | //on which we'll search for related words: |
12 | var nodeLabel = encodeURI(node.label); |
13 | |
14 | //prepare URL for XHR request: |
15 | var sUrl = "assets/ysuggest_proxy.php?query=" + nodeLabel; |
16 | |
17 | //prepare our callback object |
18 | var callback = { |
19 | |
20 | //if our XHR call is successful, we want to make use |
21 | //of the returned data and create child nodes. |
22 | success: function(oResponse) { |
23 | YAHOO.log("XHR transaction was successful.", "info", "example"); |
24 | //YAHOO.log(oResponse.responseText); |
25 | var oResults = eval("(" + oResponse.responseText + ")"); |
26 | |
27 | var query = oResults.query, |
28 | results = query && query.results, |
29 | tracks = results && results.Track, |
30 | title, url, titles, tempNode; |
31 | |
32 | if (YAHOO.lang.isArray(tracks)) { |
33 | titles = {}; |
34 | for (var i = 0, len = tracks.length; i < len; i++) { |
35 | title = tracks[i].title; |
36 | url = tracks[i].url; |
37 | |
38 | // prevent duplicate track titles by creating a hash of titles |
39 | if (!titles[title]) { |
40 | titles[title] = true; |
41 | tempNode = new YAHOO.widget.TextNode(title, node, false); |
42 | |
43 | // we can tell the tree node that this is a leaf node so |
44 | // that it doesn't try to dynamically load children. |
45 | tempNode.isLeaf = true; |
46 | |
47 | // Define a href so that a click on the node will navigate |
48 | // to the page that has the track that you may be able |
49 | // to listen to. |
50 | tempNode.href = url; |
51 | } |
52 | } |
53 | } |
54 | |
55 | //When we're done creating child nodes, we execute the node's |
56 | //loadComplete callback method which comes in via the argument |
57 | //in the response object (we could also access it at node.loadComplete, |
58 | //if necessary): |
59 | oResponse.argument.fnLoadComplete(); |
60 | }, |
61 | |
62 | //if our XHR call is not successful, we want to |
63 | //fire the TreeView callback and let the Tree |
64 | //proceed with its business. |
65 | failure: function(oResponse) { |
66 | YAHOO.log("Failed to process XHR transaction.", "info", "example"); |
67 | oResponse.argument.fnLoadComplete(); |
68 | }, |
69 | |
70 | //our handlers for the XHR response will need the same |
71 | //argument information we got to loadNodeData, so |
72 | //we'll pass those along: |
73 | argument: { |
74 | "node": node, |
75 | "fnLoadComplete": fnLoadComplete |
76 | }, |
77 | |
78 | //timeout -- if more than 7 seconds go by, we'll abort |
79 | //the transaction and assume there are no children: |
80 | timeout: 7000 |
81 | }; |
82 | |
83 | //With our callback object ready, it's now time to |
84 | //make our XHR call using Connection Manager's |
85 | //asyncRequest method: |
86 | YAHOO.util.Connect.asyncRequest('GET', sUrl, callback); |
87 | } |
view plain | print | ? |
In the codeblock above, we set up our XHR call using Connection Manager and provide the functions that should handle the data that comes back. Here are a few important items to note:
success
and failure
handlers in the argument
member of the Connection Manager callback
ojbect. That allows us to access those important pieces once we get data back from the XHR transaction.
loadNodeData
completes and returns after it fires off the request via YAHOO.util.Connect.asyncRequest
. At a later time, Connection Manager fires either the success
or failure
function we passed infnLoadComplete
function from both success
and failure
handlers. Whether the request succeeds or not, we want TreeView to stop waiting for it at some point. So, if Connection Manager fires our failure
handler, we'll treat that the same way we treat a node that has no children — we fire fnLoadComplete
and move on.You can load the necessary JavaScript and CSS for this example from Yahoo's servers. Click here to load the YUI Dependency Configurator with all of this example's dependencies preconfigured.
Note: Logging and debugging is currently turned off for this example.
Copyright © 2011 Yahoo! Inc. All rights reserved.
Privacy Policy - Terms of Service - Copyright Policy - Job Openings