Creating HTML using DOM and JavaScript

We use a lot of XML fetching in our web applications to fetch information from the server and processing it with JavaScript afterwards. What we normally do is to have a target division hardcoded in the correct location on the page and use JavaScript to add content.

The below example is taken out of context and it utilizes a custom JavaScript object that does all the dirty work and calls the processXML(boolean success) method once the XML is ready for processing. The interesting part is where the HTML is dynamically built using the createElement(String name) and appendChild(Element e) functions.

Searcher.prototype.processXML = function(success) {
  // how did we fare ?
  if (!success) {
    window.status = "Something went wrong while getting the XML while searching - aborting...";
    return;
  }

  try {
    // loop databases
    var databases = this.getElementsByTagName("database");
    if (null == databases) return;
    for (var i=0; i<databases.length; i++) {
      // get next database
      var database = databases[i];

      // get the title and path of the database
      var db_title = this.getTagValue(database.childNodes, "title");

      // get all results for database
      var results = null;
      for (var j=0; j<database.childNodes.length; j++) {
        if (database.childNodes[j].tagName == "results") {
          results = database.childNodes[j];
        }
      }

      // get result count
      var r_count = results.getAttribute("count");

      // create element for db title
      var elem_db = document.createElement("div");
      elem_db.id = "database" + i;
      elem_db.innerHTML = db_title + " (" + r_count + " resulter)";
      elem_db.className = "searchresults_database";
      elem_db.onmouseover = changeCursor;
      elem_db.onmouseout = changeCursor;
      elem_db.onclick = clickDatabase;
      this.pResults.appendChild(elem_db);

      // create element for result section (collapsed)
      var elem_results = document.createElement("div");
      elem_results.id = "results" + i;
      elem_results.className = "searchresults";
      elem_results.style.visibility = "hidden";
      elem_results.style.display = "none";
      this.pResults.appendChild(elem_results);

      // loop results
      for (var j=0; j<results.childNodes.length; j++) {
        if (results.childNodes[j].tagName == "result") {
          // get next resultsitem
          var r = results.childNodes[j];

          // get title and key
          var r_title = this.getTagValue(r.childNodes, "title");
          var r_key = this.getTagValue(r.childNodes, "key");
          var r_link = this.getTagValue(r.childNodes, "link");

          // add link anchor
          var elem_link = document.createElement("a");
          elem_link.href = r_link;
          elem_link.className = "searchresult";
          elem_link.appendChild(document.createTextNode(r_title));
          elem_results.appendChild(elem_link);
          elem_results.appendChild(document.createElement("br"));
        }
      }
    }

  } catch (exception) {
    // some error occured
    window.status = "Exception caught in Searcher.processXML(): " + exception.message;
  }
}

One thing I found out is that the Microsoft XML component allows for asynchroneous fetching. This allows you to show a progress bar or similar while loading and processing in the background.

function go() {
   // set to fetch asynchroneous
   this.pXML_data.async = true;
   // set callback method
   this.pXML_data.onreadystatechange = waitForXml;
   // go fish !!
   var success = this.pXML_data.load(url);
}

function waitForXml() {
   // wait for document to be completely loaded
   if (gXML_handler.getXmlIsland().readyState == "interactive") {
      // document has been loaded - process it
      processXML();
   }
}

function processXML() {
   // do processing...
}