Previous post
Next post

Traversing the DOM with Facebook's JavaScript

This summer, I am developing a Facebook application. It's for my honors thesis; I'm keeping the details a secret for now. I've been messing around with Facebook's API, and for the most part I think it's very developer-friendly and awesome. At least, until you start trying to modify your own DOM elements using FBJS, Facebook's filtered version of JavaScript.

For most of the JavaScript programming I do these days, I make use of jQuery, a library that simplifies the otherwise extremely tedious task of traversing through DOM elements, because the traversal functions JavaScript supplies by default are woefully lacking. Unfortunately, it is impossible to use jQuery (or another JavaScript library like Prototype) with FBJS, because Facebook modifies all the identifiers in my code, prepending them with the Facebook application ID. This means that it's impossible to get to basic JavaScript objects like window or document.

What Facebook gives you

In FBJS, you get six functions that you can call on a DOM element that give you other DOM elements: getParentNode(), getNextSibling(), getPreviousSibling(), getFirstChild(), getLastChild(), and getChildNodes(). They mirror the default JavaScript DOM element calls. FBJS also gives you document.getElementById() and getRootElement() to give you a starting point for DOM traversal. These functions are helpful, but not as helpful as they could or should be, especially when you consider one of the tips in the Facebook Developer's Wiki:

Don't create JavaScript which depends on a sensitive DOM structure. Code like this.getElementByTagName('div')[1].getFirstChild().getLastChild().setStyle('color', 'white') is very fragile and may randomly break if we change the way certain elements are rendered.

What is a hapless developer to do? Using only these functions, the only way I can get to specific DOM elements within a complicated structure is by creating long expressions like the one above. Which is exactly what I was warned against doing. Also, the code is really difficult to read.

The solution: A FBJS library

Well, that's a good ultimate goal. Until someone develops FBJQuery (it really is a good idea!), I'd like to share some FBJS functions with you that might help. children() lets you drill down through the DOM tree and collect all elements that have a specific class name and returns them as an array, and closestParent() lets you drill up through the DOM tree, returning the closest parent with a specific class name. Feel free to use them at your leisure, or modify them at your leisure, under my Creative Commons license:

/*
Mirrors the behavior of document.getElementById(name),
but it's shorter and prettier
*/
function $(name) {
  return document.getElementById(name);
}

/*
returns an array of all descendants of element
that have class "classname"
*/
function children(element, classname) {
  var list = [];
  
  function accumulateChildren(root) {
    var node = root.getFirstChild();
    while(node != null) {
      if(node.hasClassName(classname)) {
        list.push(node);
      }
      accumulateChildren(node);
      node = node.getNextSibling();
    }
  }
  
  accumulateChildren(element);
  return list;
}

/*
gets the closest ancestor of an element
that has class "classname"
*/
function closestParent(element, classname) {
  element = element.getParentNode();
  
  while(element != null) {
    if(element.getClassName() == classname) {
      return element;
    }
    element = element.getParentNode();
  }
  return null;
}

They're not much, but I hope these functions are helpful.

Comments on this post

No comments yet.

Leave your own comment