« links for 2006-06-06 | Main | links for 2006-06-07 »

Set a nested DOM property with Javascript, using square bracket notation

In the comp.lang.javascript Javascript Best Practices document, I came across an interesting discussion of the reasons for preferring square bracket notation to eval().

The consensus seems to be that eval is evil, and that "if it exists in your page, there is almost always a more correct way to accomplish what you are doing."

So instead of

eval('document.body.style'+propertyName+'='+myValue)
I could write
document.body.style[propertyName]=myValue
That is certainly cleaner, to my eye. And the bracketed syntax is Perl-ish to boot :)

But what if I want to set the value of an arbitrary property? For instance, I have a function

setProp(El, propertyName, myValue)
that is called like this:
setProp('document', 'body.style.backgroundColor', 'silver')
That sets the value of the property document.body.style.backgroundColor to 'silver'.

Likewise, if I pass different parameters:

setProp('someDiv', 'style.top', '55px')
will set the appropriate property value in the element named someDiv.

Using eval(), the body of this function could be one line:

function setProp(El, propertyName, myValue) {
    eval(El+'.'+propertyName+'='+myValue);
}

This looks convenient on paper. The thing is that each call to eval() starts a new compiler. Which is not very convenient for my users.

So I came up with another way to do the same thing, without using eval. In the process I got to apply some very simple ideas from SICP, such as storing a reference to a method in a variable. Another Lisp-ish practice that benefitted me was transforming my property string into a list.

function setNestedProperty(El, propertyName, myValue){ 
  var thePointer = El;
  for (var i=0; i < propertyName.length; i++){
    if (i == (propertyName.length - 1)){
      thePointer[propertyName[i]] = myValue;
      return;
    }
    thePointer = thePointer[propertyName[i]];
  }
}
which is called this way:

setNestedProperty('document', ['body', 'style', 'backgroundColor'], 'silver');

setNestedProperty('someDiv', ['style', 'top'], '55px');

Here is a working example of setting a nested DOM property with square bracket notation.