Search code examples
javascriptajaxfindhref

Best way to find nearest href attribute?


Why I don't think it's a duplicate.

Hmm, I think that's slightly different to what I'm asking. I don't want to add a listener to all A tags, rather, substract an href attribute, if any, on a click event's target.

I'm trying to "Ajaxify" my whole site, so that when an user clicks ANY link contained within the page, a script sends the "url" or HREF attribute (of the clicked element) to an Ajax function, which in return, renders the requested content (as indicated by the link clicked).

I need to find the HREF attribute of the clicked element, if the element is a link. The problem here, is that many elements can be contained within an A tag (because of the way I've structured them), and e.target.href doesn't necessarily always return an HREF attribute.

Here is what I have so far:

function ajaxifyLinks(e) {
    var target = e.target;
    e.preventDefault();
    while(!target.href) {
        target = target.parentNode;
    }
    if(target.href) {
        ajaxLoad(target.href);
    }
}
document.body.addEventListener('click', ajaxifyLinks);

And here are examples of different "clickable" links that I have:

<!-- Link -->
<a href="/cats">
   cats
</a>

<!-- Link -->
<a href="/hello">
   <span>
      <span> hi </span>
   </span>
</a>

<!-- Link -->
<a href="/bye">
   <span>
      bye
   </span>
</a>

As you can see, this is why e.target.href won't always return the HREF attribute, because you are actually clicking a "linked" span element, however, the browser does take you to the link. Why does this happen? And is there any way I can benefit from that behavior? (As in, extracting the location where the browser is taking you, even if you aren't clicking over an A tag).

I don't like my solution, because the while loop just keeps looking up the DOM tree, sometimes needlessly (when e.target isn't a link or contained by a link).

Thanks.


Solution

  • If the element clicked does not have an href, it searches it's parents for an element that has an href. Vanilla JS solution.

    function findUpTag(el, attr) {
        while (el.parentNode) {
            el = el.parentNode;
            if (el[attr]) {
                return el;
            }
        }
        return null;
    }
    
    document.body.onclick = function (event) {
        event.preventDefault();
    
        var href = event.target.href;
        
        if (!href) {
            var closest = findUpTag(event.target, 'href');
            if (closest) {
                href = closest.href;
            }
        }
    
        document.getElementById('output').innerHTML = 'element clicked: ' + event.target.nodeName + '<br>closest href: ' + href;
    };
    a,
    output {
        display: block;
    }
    <!-- Link -->
    <a href="/cats">
       cats
    </a>
    
    <!-- Link -->
    <a href="/hello">
       <span>
          <span> hi </span>
       </span>
    </a>
    
    <!-- Link -->
    <a href="/bye">
       <span>
          bye
       </span>
    </a>
    
    <output id="output"></output>