Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

*This has to be done in javascript, not jQuery.

What I'm trying to do is grab the innerText of the h4 tag when <a> with the class btn-blue is clicked.

I realize that I could do:

element.parentElement.previousElementSibling.children[0].innerText;

but I'm really wanting something more flexible.

This is what I have so far, and it does work when I run it in the console (chrome), but as soon as I add it to the site, it doesn't pull in the innerText of the h4 tag.

HTML

<div class="border-box clearfix">
    <div class="blah">
        <h4>h4 Title</h4>
        <p>paragraph</p>
    </div>
    <div class="head clearfix">
        <h4>h4 Title</h4>
        <p>paragraph</p>
    </div>
    <p class="float-right">
        <a href="/transactions/" class="btn-blue">anchor tag</a>
    </p>
</div>

JavaScript

    var el = document.getElementsByClassName('head')[0];
    var parent = el.parentElement;

    while(parent && parent !== document.body && parent.className && parent.className.indexOf('head'){
        parent = parent.previousElementSibling;
    }

    var children = parent.childNodes;

        for(i=0; i < children.length; i++){
            var name = children[i].tagName;
                if(name.toLowerCase() === 'h4'){
                    var text = children[i].innerText || children[i].textContent;
                        return text;
                }
        }

I believe the issue is with using parent.className.indexOf('head') in the while loop. What I'm trying to determine is if the element has the class of head, and from the SO questions (javascript - Test if an element contains a class), I've seen I can do indexOf to check and see if head is within the class.

I've also read that I can use .classList.contains('head'), but that doesn't include support for earlier IE browsers.

Two questions:

  1. Am I getting the innerText of the <h4> tag in the best possible way? (this could be better suited for codereview.stackoverflow.com).

  2. What the best way to test if a element has a class within a while loop?

SOLUTION:

I ended up using @Greg Burghardt 's solution solely because it was the easiest for me to tweak and implement for use in Google Tag Manager. The final code looked like this:

function(){
    var element   = {{gtm.element}};
    var elementClass = 'border-box';

    while(element && !((" " + element.className + " ").indexOf(" " + elementClass + " ") > -1)){
        element = element.parentNode;
    }

    return element.querySelector('h4').innerText || element.querySelector('h4').textContent;
}
share|improve this question
    
If anyone would like to play around he may fork this plunk. –  threeFourOneSixOneThree Apr 22 at 20:18
    
Will the HTML be always similar the one in your post? (I mean the hierarchy). Are there going to be 1 or multiple anchor tags in your page? –  W.D. Apr 24 at 20:10
    
@W.D. there will be multiple anchor tags throughout the page. Think of the HTML block I've provided as a one blog post out of a blog roll (multiple blog post summaries). That make sense? –  Blexy Apr 24 at 20:43
    
I've written a code which works in IE8 as well. I'll post it. Take a look at it. I'll post an example on jsfiddle, but the latter has no support of IE8 whatsoever. However my code works in IE8 (just tested it). –  W.D. Apr 24 at 20:45

3 Answers 3

up vote 1 down vote accepted
+50

How about this?

function findHeaderText(element, className) {
    while (element && !element.classList.contains(className)) {
        element = element.parentNode;
    }

    var heading = element.querySelector("h1, h2, h3, h4, h5, h6"),
        text = heading.innerHTML;

    return text;
}


function handleClick(event) {
    var text = findHeaderText(event.target, "border-box");

    alert(text);
}

The basic idea is to start at the target of the click event, and walk up the document tree until you find an element containing a certain class. From there, use the querySelector method to grab the first heading, then grab its innerHTML or text.

The function could probably use some additional error handling, but I leave that as an exercise for you. :)

share|improve this answer
    
Yeah, but you're using classList which isn't support for IE 8/9. –  Blexy Apr 24 at 19:03
    
So replace that function call with a regular express or string test. No biggie. –  Greg Burghardt Apr 24 at 20:18

I prefer to use prototype style. This OO style is easier to use and understand. But unfortunately, you can't add prototype to Element before IE8. So this solution only support IE8+ and other browsers. If you want to support IE7, you can try to change it to functional style. http://jsfiddle.net/Wa629/

Element.prototype.getParentByClassName = function(className) {
    if(!this.parentNode)
        return null;
    else if(this.parentNode.hasClass(className))
        return this.parentNode;
    else
        return this.parentNode.getParentByClassName(className);
};

Element.prototype.hasClass = function(className) {
    return (this.classList || this.className.split(' ')).contains(className);
};

Element.prototype.text = function() {
    return this.innerText || this.textContent;
};

if(!Array.prototype.contains)
{
    Array.prototype.contains = function(item) {
        for(var i = 0;i < item.length;++i)
            if(this[i] == item)
                return true;
        return false;
    }
}

Now, you can use following way to get title:

element.getParentByClassName('border-box').querySelector('.head h4').text()
share|improve this answer

Take a look at this code. This might seem a bit extended, but it does the job!

If you need explanation, I'll provide it!

DEMO

HTML

<div class="border-box clearfix">
    <div class="blah">
        <h4>h4 Title</h4>
        <p>paragraph</p>
    </div>
    <div class="head clearfix">
        <h4>h4 Title</h4>
        <p>paragraph</p>
    </div>
    <p class="float-right">
        <a href="#" onclick='return false' class="btn-blue">anchor tag</a>
    </p>
</div>


<div class="border-box clearfix">
    <div class="blah">
        <h4>h4 Title</h4>
        <p>paragraph</p>
    </div>
    <div class="head clearfix">
        <h4>h4 Title2</h4>
        <p>paragraph</p>
    </div>
    <p class="float-right">
        <a href="#" onclick='return false' class="btn-blue">anchor tag</a>
    </p>
</div>

Javascript

   function attach_(element,listener,ev,tf){

    if(element.attachEvent) {

        element.attachEvent("on"+listener,ev);

        }else{

        element.addEventListener(listener,ev,tf);

        }

    }

function getCls(clsNm){

    return clS = document.querySelectorAll ? document.querySelectorAll("."+clsNm) : document.getElementsByClassName(clsNm);

    }


function returnH4Text(el){

    wrapper = el.parentNode.parentNode;

    divs = wrapper.getElementsByTagName('div');

    if(divs.length>0){

    for(var i=0;i<divs.length;i++){

        if(divs[i].className.match('head')){

            return h4Text = divs[i].getElementsByTagName('h4')[0].innerText ? divs[i].getElementsByTagName('h4')[0].innerText : divs[i].getElementsByTagName('h4')[0].textContent;

            }

        }

    }

    }

var anchors = getCls('btn-blue');

if(anchors.length>0){

    for(var y=0;y<anchors.length;y++){

attach_(anchors[y],'mousedown',function(event){

    evt = event || window.event;
    trg = evt.target || evt.srcElement;

    alert(returnH4Text(trg));

    },false);

    }

}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.