Published: Wednesday, February 20, 2002
Enhancing the Dynamic Tree Menu System, Part 2
By Sam M. Reynoso
Read Part 1
In Part 1 we examined the changes tothe Dynamic Tree Menu System
to allow for browser compatibility (in the 6.x browser versions, at least). In this part we'll look at
some UI features that were added, as well as the added feature to allow for loading data from a database
table (as opposed to just from an XML file).
Hover Highlights
One of the simplest enhancements added to the sample was what I call a
"Hover Highlight". This handy feature changes the color of menu items as the
mouse moves over them. Not only does this look cool, but it also helps users
stay focused as they decide which item to click. Unfortunately,
this feature does not work in non-IE browsers, but I'd love to hear if anyone
finds a work-around.
To achieve the hover effect, simply add this single line to the "node" class in
the Cascading Style Sheet definition:
.node A:hover { color: #0000ff; text-decoration: none; }
|
Selected Menu Item
In the Windows Explorer you will notice that clicking a folder causes the folder's text to
change to white and take on a bold background color. I liked this feature and decided to mimic
it in the tree menu. The effect provides a visual clue that helps the user remember
which item they last clicked. Unfortunately, like the Hover
Highlights described above, this is also an IE-specific feature.
This feature is a little more complicated to implement than the Hover Highlights feature
because we need to use a combination of Javascript code and a CSS style class.
Each hyperlink in the menu has an onClick event that calls the fnSelectItem()
function:
onClick="objPreviousLink=fnSelectItem(this,objPreviousLink)"
|
When this event fires, it causes the following three things to happen:
- Removes selection indicator from the previously selected menu item
- Applies dark blue background and white text to the currently selected menu item
- Returns an object reference to the item that was clicked and stores it in
objPreviousLink
To make these things happen, the fnSelectItem() Javascript function uses a
while loop to traverse the structure of the menu's HTML code, storing a reference
to the current object and stopping when the first <TD> tag is found. It
is this tag that we need to alter in order to achieve a selected effect.
When the while loop finds the <TD> tag, it applies a new style
class to the tag:
objTD.className = "selected";
|
The selected style is defined in the Cascading Style Sheet.
The function fnSelectItem() calls fnDeselectItem() to return the style
of the previously selected menu item to normal. These two functions generally
work in the same way, except that they apply different styles.
Data Load from DB
Many developers wrote in requesting a way to load the tree dynamically with
data pulled from a database instead of from an XML file. It turns out this
is relatively simple, requiring the use of a few methods provided by the MSXML
parser.
To put an XML tree together manually instead of from an existing XML file,
we start like we did before by creating an instance of the MSXML parser
with the following line:
Set objDocument = Server.CreateObject("MSXML2.FreeThreadedDOMDocument.3.0")
|
Once we have our XML document object, we create a root node using the createElement()
method like this:
set objRootNode = objDocument.createElement("country")
|
Attributes are added to the new node with the setAttribute() method. In our example,
we add three attributes to the root node:
objRootNode.setAttribute("value") = "United States of America"
objRootNode.setAttribute("type") = "root"
objRootNode.setAttribute("url") = "content.asp?page=usa"
|
The root node is now complete, but it is lacking child nodes. Child nodes are
created using the same technique we used for the root node. In this example,
we create a child node called objStatesNode using createElement() and
setAttribute() methods.
When the child node is complete, we attach it to its parent by calling the
appendChild() method like this:
objRootNode.appendChild objStatesNode
|
If we were to print out the contents of the XML document object at this point,
it would resemble the following:
<country value="United States of America" type="root" url="content.asp?page=usa">
<states value="States" type="folder" url="content.asp?page=states"/>
</country>
|
Additional child nodes can be added by repeating this process. Once you are comfortable
with the use of these methods, it becomes easy to imagine how they could be used
in conjunction with ADO recordsets and a simple loop.
The following chunk of code shows how we can populate our new States node with a list
of state names pulled from a database table:
sql = "SELECT StateName, url, Type FROM tblStates ORDER BY StateName"
set rs_states = conn.execute(sql)
if not rs_states.eof then
'Create a node in the XML document object for each subitem
do while not rs_states.eof
set objStateNode = objDocument.createElement("state")
objStateNode.setAttribute("value") = rs_states(0)
objStateNode.setAttribute("url") = rs_states(1)
objStateNode.setAttribute("type") = rs_states(2)
objStatesNode.appendChild objStateNode 'Attach the new node to its parent
rs_states.movenext
loop
rs_states.close
end if
set rs_states = nothing
objRootNode.appendChild objStatesNode
|
Using code like this, the navigation tree can be rebuilt dynamically using data
pulled from a database instead of a static XML file. This would enable the
content of the tree to be changed based on user actions.
Now that we've examined how to load data into the tree menu system, you may be wanting to
conditionally load the data. That is, you don't want to load the data for a node in the tree
until the user clicks on it. In Part 3 we'll examine how to
accomplish this.
Read Part 3!