Search code examples
javascriptdomcss-selectorsselectors-api

Build the querySelector string value of any given node in the DOM


I am trying to find a way to build the querySelector string of any given node. In other words - pick any node on a page - is it possible to walk up the DOM and build a string that would allow me to pass the generated string to document.querySelector and get back the node I chose?

From what I can tell querySelector has a bug where you can only use nth-child once in the string.

I have tried several times but so far have failed to find a solution. I want to do this in native JavaScript, not jQuery.Any suggestions?


Solution

  • I see this question is from 2015 but I just dealt with this issue and had to build a custom function to do so.

    I've made a snippet to test it, just click any element and the querySelector should display as a string in the bottom div.

    function getQuerySelector(elem) {
    
      var element = elem;
      var str = "";
    
      function loop(element) {
    
        // stop here = element has ID
        if(element.getAttribute("id")) {
          str = str.replace(/^/, " #" + element.getAttribute("id"));
          str = str.replace(/\s/, "");
          str = str.replace(/\s/g, " > ");
          return str;
        }
    
        // stop here = element is body
        if(document.body === element) {
          str = str.replace(/^/, " body");
          str = str.replace(/\s/, "");
          str = str.replace(/\s/g, " > ");
          return str;
        }
    
        // concat all classes in "queryselector" style
        if(element.getAttribute("class")) {
          var elemClasses = ".";
          elemClasses += element.getAttribute("class");
          elemClasses = elemClasses.replace(/\s/g, ".");
          elemClasses = elemClasses.replace(/^/g, " ");
          var classNth = "";
    
          // check if element class is the unique child
          var childrens = element.parentNode.children;
    
          if(childrens.length < 2) {
            return;
          }
    
          var similarClasses = [];
    
          for(var i = 0; i < childrens.length; i++) {
            if(element.getAttribute("class") == 
    childrens[i].getAttribute("class")) {
              similarClasses.push(childrens[i]);
            }
          }
    
          if(similarClasses.length > 1) {
            for(var j = 0; j < similarClasses.length; j++) {
              if(element === similarClasses[j]) {
                j++;
                classNth = ":nth-of-type(" + j + ")";
                break;
              }
            }
          }
    
          str = str.replace(/^/, elemClasses + classNth);
    
        }
        else{
    
          // get nodeType
          var name = element.nodeName;
          name = name.toLowerCase();
          var nodeNth = "";
    
          var childrens = element.parentNode.children;
    
          if(childrens.length > 2) {
            var similarNodes = [];
    
            for(var i = 0; i < childrens.length; i++) {
              if(element.nodeName == childrens[i].nodeName) {
                similarNodes.push(childrens[i]);
              }
            }
    
            if(similarNodes.length > 1) {
              for(var j = 0; j < similarNodes.length; j++) {
                if(element === similarNodes[j]) {
                  j++;
                  nodeNth = ":nth-of-type(" + j + ")";
                  break;
                }
              }
            }
    
          }
    
          str = str.replace(/^/, " " + name + nodeNth);
    
        }
    
        if(element.parentNode) {
          loop(element.parentNode);
        }
        else {
          str = str.replace(/\s/g, " > ");
          str = str.replace(/\s/, "");
          return str;
        }
    
      }
    
      loop(element);
    
      return str;
    
    
    }
    

    https://jsfiddle.net/wm6goeyw/