Accessing HTML Elements that have been created by setting innerHTML

Refresh

December 2018

Views

1.3k time

1

I have a Function which makes an ajax call and then return a piece of html that is inserted into a table's td element. using element.innerHTML=ajaxResult; Now I want to access the elements in the ajaxResult that have the name attribute as special. So I do a document.getElementsByName('special') and expect to get 4-5 elements. But I actually get none.

This makes it impossible for me to access those elements and I am stuck. Please help me resolve this. Thanks in Advance!

I think this is related to the dom not reloading after I set innerHTML. But not sure how to reload it.

I am using IE8 in IE8 compatibility view and IE7 standards :(

EDIT

This is my function

function handleStateChange()
{
    if(ajaxRequest.readyState==4 && ajaxRequest.status==200) {                 
        var responseStr = ajaxRequest.responseText;
        var splitResult = responseStr.split("$$$$$$$$$$$$$$$$$$$$");
        var leftHtml= splitResult [0];
        var rightHtml= splitResult [1];
        document.getElementById("div1").innerHTML=leftHtml;    

        if(rightHtml !="") {
            document.getElementById("div2").innerHTML=rightHtml;
       }


       if(splitResult.length >=3 ){
           var appActionflag = splitResult [2];
           document.getElementById("userAction").innerHTML=appActionflag;
       }

       if(splitResult.length >= 4 ){
           var userId = splitResult [3];
           document.getElementById("userId").innerHTML=userId;
       }

       reverseDNASwitch();
        var grpList = document.getElementsByName('parmGrpId');

        alert('javascript is working! Found:'+grpList.length);

        for(var i=0;i<grpList.length;i++){
           alert('Got GroupId: '+ (i));
           var grpTd = grpList[i];
           grpTd.innnerHTML='Hi';
        }
    }
}

2 answers

3

If the table cell you're adding to is, itself, in the DOM, that should work. (And so I may have to delete this answer; originally I thought document.getElementsByName had been deprecated, but I was mistaken). Here's an example using getElementsByName:

Live Copy | Live Source

(function() {
  // Get the target
  var target = document.getElementById("target");

  // Dynamically add content
  target.innerHTML =
    '<div name="special">special 1</div>' +
    '<div name="special">special 2</div>' +
    '<div name="special">special 3</div>';

  // Get those elements
  var list = document.getElementsByName("special");

  // Prove we got them
  var p = document.createElement('p');
  p.innerHTML = "Found " + list.length + " 'special' elements";
  document.body.appendChild(p);
})();

Of course, because it's a function of document, that will find all of the elements with name="special", not just the ones you added to the table cell.

The above does not work on IE if the elements aren't allowed to have the name attribute. So for instance, if you look for getElementsByName("special"). it will ignore <div name="special"> but find <input name="special">, because name is not a valid attribute for div elements. Details in this MSDN article. Worse, IE will include elements whose id matches, even though of course that has nothing to do with name. sigh

Unless you need to support IE7 and earlier (e.g., unless you're developing for China), you can use Element#querySelectorAll with the selector '[name="special"]'. That will look only within the element for elements that use that name attribute.

Example: Live Copy | Live Source

(function() {
  // Get the target
  var target = document.getElementById("target");

  // Dynamically add content
  target.innerHTML =
    '<div name="special">special 1</div>' +
    '<div name="special">special 2</div>' +
    '<div name="special">special 3</div>';

  // Get those elements
  var list = target.querySelectorAll('[name="special"]');

  // Prove we got them
  var p = document.createElement('p');
  p.innerHTML = "Found " + list.length + " 'special' elements";
  document.body.appendChild(p);
})();

If you need to support IE7 or earlier, you might look at this other Stack Overflow question and my answer to it. The question points to this article about adding querySelectorAll to document, and my answer to the question talks about how to emulate that at an element-specific level.

So combining the code from that article with my answer to the other question and the examples above, we get:

Live Copy | Live Source

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
  <div id="target"></div>
  <script>
    (function() {
      // IE7 support for querySelectorAll. Supports multiple / grouped selectors and the attribute selector with a "for" attribute. http://www.codecouch.com/
      if (!document.querySelectorAll) {
        (function(d, s) {
            d=document, s=d.createStyleSheet();
            d.querySelectorAll = function(r, c, i, j, a) {
                a=d.all, c=[], r = r.replace(/\[for\b/gi, '[htmlFor').split(',');
                for (i=r.length; i--;) {
                    s.addRule(r[i], 'k:v');
                    for (j=a.length; j--;) a[j].currentStyle.k && c.push(a[j]);
                    s.removeRule(0);
                }
                return c;
            }
        })();
      }

      var qsaWorker = (function() {
          var idAllocator = 10000;

          function qsaWorkerShim(element, selector) {
              var needsID = element.id === "";
              if (needsID) {
                  ++idAllocator;
                  element.id = "__qsa" + idAllocator;
              }
              try {
                  return document.querySelectorAll("#" + element.id + " " + selector);
              }
              finally {
                  if (needsID) {
                      element.id = "";
                  }
              }
          }

          function qsaWorkerWrap(element, selector) {
              return element.querySelectorAll(selector);
          }

          // Return the one this browser wants to use
          return document.createElement('div').querySelectorAll ? qsaWorkerWrap : qsaWorkerShim;
      })();

      // Get the target
      var target = document.getElementById("target");

      // Dynamically add content
      target.innerHTML =
        '<div name="special">special 1</div>' +
        '<div name="special">special 2</div>' +
        '<div name="special">special 3</div>';

      // Get those elements
      var list = qsaWorker(target, '[name="special"]');

      // Prove we got them
      var p = document.createElement('p');
      p.innerHTML = "Found " + list.length + " 'special' elements";
      document.body.appendChild(p);
    })();
  </script>
</body>
</html>

Which works in IE7.

1

As an option for your specific scenario, where you want to get elements with a specific attribute (and value), you can use a function like this:

function getElementsByAttribute(options) {
    /*if (container.querySelectorAll) {
        var selector = '';
        if (options.tagFilter) {
            selector += options.tagFilter;
        }
        selector += '[' + options.attr;
        if (options.val) {
            selector += '="' + options.val.replace(/"/g, '\\"') + '"';
        }
        selector += ']';
        return Array.prototype.slice.call(options.container.querySelectorAll(selector));
    }*/
    var elements = options.container.getElementsByTagName(options.tagFilter || "*"),
        ret = [],
        i, cur,
        matches = (function () {
            if (options.val) {
                return function (el) {
                    return el.getAttribute(options.attr) === options.val;
                };
            } else {
                return function (el) {
                    return el.hasAttribute(options.attr);
                };
            }
        })();
    for (i = 0; i < elements.length; i++) {
        cur = elements[i];
        if (matches(cur)) {
            ret.push(cur);
        }
    }
    return ret;
}

And you call it like:

window.onload = function () {
    var contain = document.getElementById("container"),
        els = getElementsByAttribute({
            container: contain,
            attr: "name",
            val: "special",
            tagFilter: ""
        });

    console.log("els", els);
};

DEMO: http://jsfiddle.net/cxq6t/1/

(I kept in my original logic for supporting querySelectorAll, but proved not to work in old IE with invalid attributes, per the comments)

The object you pass to the function accepts:

  • container: containing element to look through
  • attr: the attribute to look for
  • val: optional value to match against
  • tagFilter: optional filter for the tagName of matched elements

I tested in IE7/8 to see if the <div name="special"> would match, and it does. As well as the other <input />s.

If you ever wanted to expand the selector to be more complicated things like what querySelectorAll supports, you could use a polyfill like T.J.Crowder's. But this seems to get the job done.

Ian