A coworker once asked me about a grid
control that he could use to sort data. He was looking for a method
by which he could take a parent node’s child nodes and move them to
a different parent node. I couldn’t think of a particular control,
but I said that he could easily create this functionality by using
XML and Internet Explorer’s data-binding behavior. This article
outlines the method I used to help my coworker achieve his
task.

One of IE’s best features is its ability to
bind data in XML data islands to particular HTML elements,
especially <TABLE> elements. You can easily display
hierarchical data by nesting more tables within parent tables. By
nesting a table within another table and binding the data to the
XML data island, I was able to accomplish my coworker’s task easily
and quickly.

The appendChild() method of the DOMDocument
class (which the XML data island implements) also helps me with
this task. I can take a parent node’s child node and use the
appendChild() method of the new parent node to attach the child
node to the new parent. When this happens, the child node is
“physically” removed from the previous parent node and added to the
new parent node. Above and beyond that, IE automatically updates
the bound elements, namely the <TABLE> element. The only
thing left to do is add the method by which the user will interact
with the data. You can do this with drag-and-drop.

In my table, I need a drag source to drop in
the new parent. If I use a <SPAN> element, which is the
element that will be bound to the child data, I’ll have to select
the text within the span to create the TextRange that will become
the drag source. However, images make nice drag sources. Each child
row will contain an <IMG> tag that will give me the
drag-and-drop functionality that I’ll need.

In order to allow the <TR> element that’s
bound to the parent node to become a drop target, I must add event
handlers for the drag and drop events. I’ll disable the default
ondragenter and ondragover event handlers of the row by the
returnValue of the event object to false:

<tr . . .
ondragenter=”window.event.returnValue=false”
ondragover=”window.event.returnValue=false”>

And, I’ll add a custom event handler for the
ondrop event. This event handler will be responsible for finding
the parent node within the DOM and appending the selected
child.

In order to select the child, I have to create
an event handler for the ondragstart event of the <IMG> tag.
This event handler is responsible for selecting the child node that
will be moved.

Now that you have the foundation for the page,
I’ll create the code:

<html>
<head>
<script language=”JavaScript”>

var childrenNode = null;

function img_ondragstart(element) {
    var childId =
element.parentElement.all.hdnChild.value;
    childrenNode =
xmlTest.selectSingleNode(“//children[id='” + childId +
 “‘]”);
}

function tr_ondrop(element) {
    if (childrenNode == null) return;
    var dadId =
element.all.hdnDad.value;
    var parentNode =
xmlTest.selectSingleNode(“//parent[id='” + dadId + “‘]”);
    parentNode.appendChild(childrenNode);

    childrenNode = null;
}

</script>
</head>
<body>
<xml id=”xmlTest” name=”xmlTest”>
<root>
    <parent>
        <id>1</id>

        <dad>John</dad>

        <children>

            <id>1</id>

           
<child>Mary</child>
        </children>

        <children>

            <id>2</id>

           
<child>Sally</child>
        </children>

    </parent>
    <parent>
        <id>2</id>

        <dad>Jim</dad>

        <children>

            <id>3</id>

           
<child>David</child>
        </children>

        <children>

            <id>4</id>

           
<child>George</child>
        </children>

    </parent>
</root>
</xml>

<table id=”tblMain” cellpadding=”0″ cellspacing=”0″
border=”1″
 dataSrc=”#xmlTest”>
<tr ondrop=”tr_ondrop(this)”
ondragenter=”window.event.returnValue=false”
 ondragover=”window.event.returnValue=false”>
    <td colspan=”2″>
        <input
type=”hidden” id=”hdnDad” dataFld=”id”>
        <span
dataFld=”dad”></span>
    </td>
</tr>
<tr>
    <td
style=”width:50px;”>&nbsp;</td>
    <td>
        <table
cellpadding=”0″ cellspacing=”0″ border=”1″ dataSrc=”#xmlTest”
 dataFld=”children”>
        <tr>
            <td>

                <img
src=”reddot.gif” ondragstart=”img_ondragstart(this)”
 width=”15″ height=”15″>
                <input
type=”hidden” id=”hdnChild” dataFld=”id”>
                <span
dataFld=”child”></span>
            </td>

        </tr>
        </table>

    </td>
</tr>
</table><br>

</body>
</html>

If you inspect the tables within the code,
you’ll notice that the outer table consists of two rows. The first
row contains one cell that spans two columns. In this cell, I place
the <SPAN> element that binds to the data that I want to
display. A hidden <INPUT> element is added for the unique
identifier <id/>. I use this value to locate the node within
the DOM using XPath.

The second row contains two cells: One is a
blank cell that serves as a spacer so you can see the levels of
hierarchy better, and the other contains the <SPAN> and
hidden <INPUT> elements that I use just like in the previous
row. It also contains the <IMG> tag that I use as the drag
source.

When you look at the JavaScript, you’ll see the
two simple event handlers that create the drag-and-drop
functionality. The img_ondragstart() function locates the
associated <children> node within the DOM and sets a public
variable to that node. The tr_ondrop() function first checks to
make sure there’s a child node to move, and then locates the
<parent> node within the DOM. It then appends the child node
to the located <parent> node. Then, it resets the public
variable for good measure.

The XML data island’s structure must follow the
conventions used to bind XML data to <TABLE> elements. This
means that each row on the outer table is bound to the repeating
child nodes of the root node. Each row of the nested table is bound
to the repeating child nodes of the node bound to the row of the
outer table. To bind the inner table, you must specify the dataFld
attribute of the <TABLE> element.

Be sure to check out
this example online
.

Keep your developer skills sharp by automatically signing up for TechRepublic’s free Web Development Zone newsletter, delivered each Tuesday.