Search code examples
javascriptdom-events

Generate ID dynamically based on position in DOM


I need to generate a value of element based on the level in the DOM. e.g. If I have a click event at document level (i.e. listening to any clicks on the pages) and the rendered HTML like this, it needs to traverse through DOM until you see "ID" attribute populated.

<div id="someid">
<div>
    <span>
        <p>
            <a href="javascript:void(0);">
                <span>
                    <strong>Googlie</strong> 
                </span>
            </a>                
        </p>
    </span>
</div>

When I click on "Googlie", it should generate something like this: someid__div_span_p_a_span_strong

Issue:
I do have some code to do this but there is a problem with it. In above, what if I have two elements, right after another as shown below. How do I generate an unique value for strong element? Can I have something without using childNodes location? The childNodes value changes if someone changes the white space between the elements.

...<span>
<strong>Googlie</strong> <br/> <strong>Bingie</strong>
</span>...

    document.onclick = function(obj) {
    var node = obj.target;
    var res = [];
    var etA = "";
    res[0] = false;
    while (!res[0]) {
        res = GetIdFor(node);
        if (!res[0]) {
            var end = node.parentNode.childNodes.length;
            for (var i = 0; i < end; i++) {
                var j = node.parentNode.childNodes[i];
                if (j.nodeType === 1 && j === node) {
                    break;
                }
            }
            etA = "_" + node.tagName + etA;
            node = node.parentNode;
        }
        else {
            etA = res[1] + "_" + etA;
        }
    }
    alert(etA);
};
function GetIdFor(elem) {
    var res = [];
    res[0] = false;
    var d = elem.getAttribute("ID");
    if (d !== "undefined" && d !== null) {
        res[0] = true;
        res[1] = d;
    }
    return res;
}

Now, I know jQuery can help here but that's not THE point. :) Thoughts? Do I not have any other choice but using childNodes level in order to generate this value?


Solution

  • I adapted this answer from Here. The author suggests putting [#] as a sibling number so that you can differentiate between siblings, e.g. someid__div_span_p_a_span_strong[0]

    Working jsFiddle Here.

    function elementPath(element)
    {
        return $(element).parents().andSelf().map(function() {
            var $this = $(this);
            var tagName = this.nodeName;
            if ($this.siblings(tagName).length > 0) {
                tagName += "[" + $this.prevAll(tagName).length + "]";
            }
            return tagName;
        }).get().join(".").toLowerCase();
    }
    
    $(document).ready(function() {
        $(document).click(function(e) {
            e.stopPropagation();
            window.alert(elementPath(e.target));
        });
    });