Build an Ajax Tree with YUI

    Darrin Koltow
    Darrin Koltow

    jQuery may be the cool kid on the block when it comes to JavaScript libraries, but there are a number of serious contenders out there—not the least of which is Yahoo’s YUI (Yahoo User Interface) library. It includes a full range of functionality: DOM manipulation, Ajax helpers, rich interface widgets … the works!

    When you code with YUI, you’re leveraging a ton of freely available, proven code with supporting documentation. You should consider yourself fairly safe using code backed by one of the biggest players on the Web.

    In this article we’ll look at two separate pieces of the YUI puzzle, and how they can be combined to create a cool piece of functionality. Specifically, we’ll be working with the YUI TreeView component, which is a way of presenting a dynamic hierarchical tree in the browser. But we’ll also be looking into YUI’s Ajax helpers, as we’ll be fleshing out the limbs of the tree dynamically with Ajax calls.

    The project we’ll undertake in this article will create an instance of the TreeView component that has only one text node to begin with. When the user clicks on this node, an Ajax request is fired off to find a list of synonyms for the clicked word. Our code will create new nodes on the tree for each synonym returned. Each new node, in turn, will be clickable to create its own subtree of synonyms.

    Before undertaking this project, you’ll want to have at least some literacy or skill in JavaScript, especially object oriented JavaScript (for an extensive introduction to the latter, you can check out this article by Ryan Frishberg).

    The complete ZIP code archive for this tutorial can be downloaded here.


    The core method we’ll be using in this tutorial is the asynchronous call to the synonym-searching script. We use the YUI Connection Manager to make that call:

    YAHOO.util.Connect.asyncRequest('GET', stringURL, objectCallBack, null);

    As this is an asynchronous request, once the call is made, control flow immediately returns to execute statements following asyncRequest.

    Let’s have a look at the arguments to this method. The first two arguments consist of the type of the request (GET, in this case) and the URL to which the request is being made. We’ll come to the third argument in a moment, and argument four is only required for POST transactions, so that stays null for our example.

    The key argument is objectCallBack. Here’s its structure:

    {  success: funcToDoOnSuccess,  failure: funcToDoOnFailure,  argument: { "argForSuccessOrFailureFuncs": myObject },  timeout: 7000};

    We first need to define methods to be run on a successful request (success), or an error (failure). In the example above, the asyncRequest method calls the function funcToDoOnSuccess if its GET request is successful; for an unsuccessful GET request, it will call the function funcToDoOnFailure (for example, in the event of a 404 Page Not Found error).

    In the argument property we place the data that these methods will need to do their jobs. When the asyncRequest method calls either of our callback functions (funcToDoOnSuccess or funcToDoOnFailure), it will use whatever you specify here as the argument to pass to that function.

    As we work through the tutorial, we’ll be replacing the above generic example parameters with the ones needed to build our synonym tree.

    Linking to the YUI Library

    Before we can use any YUI objects, we have to link to the YUI JavaScript library. Fortunately, Yahoo provides Content Delivery Network (CDN) hosting for all the JavaScript and CSS files required, as well as providing a great interface for creating a custom link that will include only the needed functionality.

    Head over to the Yahoo Dependency Configurator, and select Connection Manager Full from the YUI JavaScript Utilities section, as well as TreeView Control from the YUI User Interface Widgets section. At the bottom of the page you’ll be provided with a snippet of code like this:

    <!-- Combo-handled YUI CSS files: --><link rel="stylesheet" type="text/css" href="…"><!-- Combo-handled YUI JS files: --><script type="text/javascript" src="…"></script>

    I’ve omitted the URLs from the above code example as they’re extremely long, and it’s best to construct your own URL with the functionality you need. The advantage of this is that you can easily include any other YUI components you need without adding additional style sheets or script files. Just head back to the configuration app and generate a new set of links!

    Simply copy the HTML snippet you receive into the head of your document, and you’re set to make a start with YUI.

    Creating the Initial Tree

    The first step is to create a function that will build the TreeView widget object. Initially, it will contain just one text node containing the label “apple.” When the user clicks that node, our code will build a subtree under it, populating it with synonyms for “apple.”

    In the following code fragment, notice first the lines without bold. We create the tree with the TreeView’s constructor, whose argument is the HTML element in which we’ll build the tree (AjaxTreeDiv). The getRoot call receives a reference to the tree’s root and passes it to the TextNode’s constructor. Giving the root to the new node connects the tree; it creates a link back to the parent. We do the actual drawing of the tree with its render method.

    We start by declaring some variables. obNode will be the node object, obAjaxTree will be the tree object, and treeRoot will be used to hold a reference to the tree’s root node.

    We call the TreeView’s constructor (YAHOO.widget.TreeView), passing in the HTML element in which we want to build the tree (AjaxTreeDiv).

    The highlighted statement is the one that should grab most of our attention. The setDynamicLoad method tells the tree that we want to know when the user clicks on one of its nodes to expand it, and it tells the tree what function to call (makeMoreNodes, which we’ll be writing shortly) when those clicks happen:

    function buildAjaxTree() {   var obNode;  var obAjaxTree;  var treeRoot;    obAjaxTree = new YAHOO.widget.TreeView ("AjaxTreeDiv");  obAjaxTree.setDynamicLoad(makeMoreNodes,0);  treeRoot = obAjaxTree.getRoot();  obNode = new YAHOO.widget.TextNode("apple", treeRoot, false);  obAjaxTree.render();}

    After setting that option, we store a reference to the tree’s root in treeRoot, and create a new TextNode. Passing the treeRoot variable to the TextNode constructor connects the node with the tree. Finally, we call the render method to display the tree.

    Notice that all of this code is inside a function, which we’ve called buildAjaxTree. Here’s the statement that will call it:


    This is the first statement of our code that will be executed. The onDOMReady method calls buildAjaxTree when the HTML page is fully loaded. Running our script before that point would invite errors.

    Making More Nodes with Ajax Calls

    Now let’s walk through the makeMoreNodes function. First, refer back to the overview of the callback object described in the beginning of this article. Remember that our Ajax call (asyncRequest) needs a callback object with success and failure methods, so it can call one of those methods after its data gathering mission. Most of the code inside makeMoreNodes works to create that callback object.

    Here’s the callback object we’ll be using. Compare it with the generic callback object we saw when introducing asyncRequest:

    var obMkNodesCb = {  success: foundSynonyms,  failure: foundNoSynonyms,  argument: {     "node": nodeToAddTo  },  timeout: 7000};

    The success and failure properties refer to the methods that asyncRequest will call after it queries our server-side thesaurus script. We will call the foundSynonyms function if the PHP script succeeds in pulling in some synonyms, or the foundNoSynonyms callback if the PHP script fails in its search. Note that the timeout property is a factor in this failure case: asyncRequest flags a failure if it fails to receive results within seven seconds (7,000 milliseconds) of being called.

    The argument Property

    The asyncRequest method requires that the argument property be a part of the callback object. Remember that the argument property contains whatever data is needed by the success and failure functions called by asyncRequest. For our example, prior to the Ajax call, we store the node clicked by the user in argument. The success method needs this node for two reasons. Firstly, to build the new synonym subtree: a root node is needed for this, and the node clicked by the user will be that root. Secondly, to tell the node we’re done using it, through its loadComplete method. If we didn’t fire that method, the tree would freeze, because one of its nodes wouldn’t know when to resume listening for the user’s mouse clicks.

    The failure method needs to have access to the clicked node for the same reason. Even though the failure method adds no nodes to the tree, the node the user clicked on still needs its loadComplete method called, so it can start listening for user clicks again.