Thursday, February 03, 2011

For .... with innerhtml

I want to talk about a very simple fact about DOM manipulation using javascript. This is not specific to mobile but is applicable to all the browser in general.

On a higher level, I want to append three child elements (div) to a div container. I also want to hold a reference in javascript as I want to add/manipulate their content. My javascript was as follows:
var domContainer = new Array();
var n = 3;
var p = document.getElementById("parent");
for(var i=0;i<n;i++)
{
var cntId = "cnt"+i;
p.innerHTML += "<div id='"+cntId+"'></div>";
domContainer[i] = document.getElementById(cntId);
}

Essentially, I first got hold of the parent container and then changed the inner html of the container to add a child. As soon as I append the child, I get the hold of the child element and store it in the array. To manipulate the content of a child element with index i, I did
domContainer[i].innerHTML = "dummy content";

To my surprise, for all child container with index < n-1 (in this case for i=0 and 1), browser never displayed the dummy content. It also never fired any javascript error. Interesting, isn't it ? What is happening is here when we are changing the innerHTML of the parent container, it is destroying all the existing child elements of the container and recreating them again along with appending the new child element. From browser perspective, this is what is happening:

for i=0, it is creating a child element to parent container with id as cnt0;
for i=1, it is destroying the existing child element with id cnt0 and then creating two child elements with id cnt0 and cnt1.
for i=2, it is destroying the existing child elements with id cnt0 and cnt1 and then creating three child elements with id cnt0, cnt1 and cnt2.

Note that the browser just destory those elements from UX but do not remove it from browser memory as javascript is still holding a reference to those dom objects (in domContainer array). Therefore, by the end of the loop all the values in array for index 0 to n-2 refers to a DOM element which is still in browser memory but are no longer displayed to the user. Since child elements are not re-created after the end of the loop, therefore the element at index n-1 is the same as the one that is currently being displayed. This explains the behavior I was observing. So how did I fixed this ?
for(var i=0;i<n;i++)
{
var cntId = "cnt"+i;
var cnt = document.createElement("div");
cnt.setAttribute("id", cntId);
p.appendChild(cnt);

domContainer[i] = document.getElementById(cntId);
}