2

I am new to javascript. I have a table of content which I want to rearrange its row and column based on user's window size using window.onresize.

window.onresize = function () {

    var w = window.innerWidth;
    var nocolumn = Math.floor(w / 252);
    if (nocolumn == 0) {
        nocolumn = 1;
    }

    var table = document.getElementById("MainContent_DataList1");
    var tbody = table.getElementsByTagName("tbody")[0];
    var link = tbody.getElementsByTagName("a");

    var norow = Math.ceil(link.length / nocolumn);
    tbody.innerHTML = "";

    console.log(norow + " " + link.length + " " + nocolumn);
    for (var i = 0; i < norow; i++) {
        var row = document.createElement("tr");
        tbody.appendChild(row);
        for (var j = 0; j < nocolumn; j++) {
            var cell = document.createElement("td");
            row.appendChild(cell);
            if ((i * nocolumn + j) < link.length) {
                cell.appendChild(link[i * nocolumn + j]);
            }
        }
    }
};

I dont understand why the variable "link" array becomes empty after I use innerHTML = ""; but I stored it before its cleared. Is it somewhere I did wrongly or there are other ways to do this?

1
  • 1
    Can you post the full page or link to jsfiddler ? Commented Jun 17, 2013 at 2:28

2 Answers 2

1

When you delete the innerHTML you delete the DOM objects thus every reference to them will point to null.

A work around it will be to clone these objects:

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = {};
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

window.onresize = function () {

    var w = window.innerWidth;
    var nocolumn = Math.floor(w / 252);
    if (nocolumn == 0) {
        nocolumn = 1;
    }

    var table = document.getElementById("MainContent_DataList1");
    var tbody = table.getElementsByTagName("tbody")[0];
    var tmp = tbody.getElementsByTagName("a");
    var link = clone(tmp);

    var norow = Math.ceil(link.length / nocolumn);
    tbody.innerHTML = "";

    ...
}

Credit for the clone() method: https://stackoverflow.com/a/728694/1057429

Sign up to request clarification or add additional context in comments.

9 Comments

Far simpler (and safer) to iterate over the NodeList by index and assign to an array (i.e. convert the NodeList to an array).
When you delete the innerHTML you delete the DOM objects thus every reference to them will point to null. is incorrect. They are removed from the NodeList created by getElementsByTagName, other references not involving a live NodeList are unaffected (such as assigning references from an array or using querySelectorAll, which creates static NodeLists).
@RobG maybe I'm missing something but if you'll try to debug his code, when you'll get to tbody.innerHTML = ""; you can inspect the value of link and see that it becomes null
@RobG and about your first comment - I totally agree with you, for this specific case it'll be enough to convert the NodeList to an array, but I was aiming to provide a solution that will be more generic and can be in other cases of DOM elements as "an input" as well.
wow thanks all the quick answers! i didn't know i could clone these objects. i got it working already!
|
0

As other answers have suggested, getElementsByTagName returns a live NodeList. Therefore, when you delete all the elements from the body, the NodeList is updated to contain no nodes.

As an alternative, you can use querySelectorAll, which returns a static NodeList, or use getElementsByTagName and assign references to an array before clearing the nodes from the body, e.g.

function getNodes() {
  var tbody = document.body || document.getElementsByTagName('body')[0];
  var nodes, link;

  if (tbody.querySelectorAll) {
    link = tbody.querySelectorAll('*');
  } else {
    nodes = tbody.getElementsByTagName("*");
    link = [];

    for (var i=0, iLen=nodes.length; i<iLen; i++) {
      link[i] = nodes[i];
    }
  }
  return link;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.