The Web Professional's Handbook: Document Object Models -WebReference.com- | 15

The Web Professional's Handbook: Document Object Models

Adding and Removing Nodes

The reason for accessing a certain element is usually that you want to change, move, clone, or delete the element. The following example script allows the user to add sets of form fields in a CD review form, or to delete them.

Initially there's only enough room for reviewing one CD…

…but when the user clicks the 'Give me more fields!' button, a new set of form fields appears. Attached to the button is a script that copies a template of the set of form fields and adds this copy to the document. The browser immediately reacts by showing it. When the 'Remove review' button is clicked, a script similarly removes the set of form fields from the document.

First of all, let's take a look at the HTML. The form itself is plain and simple. However, there are two extra elements in it.

<div id="readroot" style="display: none">
  <p class="hr">&nbsp;</p>
  <input type="button" value="Remove review" style="font-size: 10px"
         onClick="this.parentNode.parentNode.removeChild(this.parentNode);" />
  <br /><br />
  <input name="cd_1" value="title" />
  <select name="rankingsel_1">
    <option>Rating</option>
    <option value="excellent">Excellent</option>
    <option value="good">Good</option>
    <option value="ok">OK</option>
    <option value="poor">Poor</option>
    <option value="bad">Bad</option>
  </select>
  <br /><br />
  <textarea name="review_1">Short review</textarea>
</div>
<form action="storereviews.pl">
  <span id="writeroot"></span>
  <input type="button" value="Give me more fields!" onClick="moreFields()" />
  <input type="button" value="Send form" onClick="alert('Fake submit')" />
</form>

Now for the actual script. We first set a variable counter, which will count the number of clones made. After all, each form field should have a unique name. By appending the value of counter to the default names of the fields, we make sure that each name is unique.

var counter = 0;

Next we have the function that clones the set of form fields and adds the clone to the document. It first checks whether the W3C DOM is supported by seeing if the browser understands getElementById() and insertBefore(). If it doesn't, it ends the function by a return. If it does, then we make a new set of the form fields, so we increase counter by one.

function moreFields()
{
  if (!document.getElementById && !document.insertBefore)
  {
    return;
  }
  counter++;

We take the element with id attribute "readroot" and clone it using the cloneNode() method. We reset its id value (an id should be unique, after all) and set its display style to block so that it will be visible.

  var newFields = document.getElementById('readroot').cloneNode(true);
  newFields.id = 'clone' + counter;
  newFields.style.display = 'block';

Having cloned the set of form fields, we now make sure that each field has a unique name. We go through all children of the cloned <div>. Every form field has a name, so we see if the current child node has a name attribute. If it has, we remove the last character of its name (the number) and add the current value of counter. Now the form field has a unique name.

  var newField = newFields.childNodes;
  for (var i=0;i<newField.length;i++)
  {
    var theName = newField[i].name
    if (theName)
    {
      newField[i].name = theName.substring(0,theName.length-1) + counter;
    }
  }

The set of form fields is now ready to be inserted. We insert it just before the <span> with id attribute "writeroot".

  var insertHere = document.getElementById('writeroot');
  insertHere.parentNode.insertBefore(newFields,insertHere);
}

In the final part of the script, we call this function once the page has loaded, so that the user will initially see one set of form fields.

window.onload = moreFields;

Remember from the HTML that each set of form fields has its own " Remove review" button:

  <input type="button" value="Remove review" style="font-size: 10px"
        onClick="this.parentNode.parentNode.removeChild(this.parentNode);" />

When it is clicked, the button's parent node (the <div>) is removed from its own parent node (the <form>). Thus the review disappears completely from the document and cannot be retrieved.

As a summary, here are the W3C DOM methods that help to add and remove nodes:


Method

Description

Example

appendChild()

Append  a node to another node as its last child node. If the element is already in the document, it is removed from its previous position. Use insertBefore() to append a node in another position than as the last child.

x.appendChild(y):
Append node y as the last child of node x.

cloneNode()

Clone  a node. If an argument of true is passed, its descendants are also cloned. If an argument of false is given, no descendent nodes are cloned.

var x = y.cloneNode(true):
Clone node y, including its children, and temporarily store the clone in x. (Later x can be added to the node tree.)

createElement()

Create a new element.

var x =
  document.createElement('p')
:
Create a new <p> tag and temporarily store it in x. (Later, x can be added to the node tree.)

createTextNode()

Create a new text node.

var x =
document.createTextNode('text')
:
Create a new text node with value text and temporarily store it in x. (Later, x can be added to the node tree.)

insertBefore()

Insert  a node into the document tree as a child node, before the existing child node specified.

x.insertBefore(y,z):
Insert node y into the document as a child of node x, just before node z.

removeChild()

Remove a child node from the node tree.

x.removeChild(y):
Remove child node y of node x.

replaceChild()

Replace a child node with another node.

x.replaceChild(y,z):
Replace node z, a child of node x, by node y.

setAttribute()

Set the value of an attribute. There are several serious browser-compatibility problems with this method, so don't use it unless there is no other way to set an attribute. In the next table you'll find code to set the most common attributes of an element (id, class, and title).

x.setAttribute('align','right'):
Set the align attribute of node x to 'right'.


Created: March 11, 2003
Revised: March 28, 2003

URL: http://webreference.com/programming/professional/chap6/2