*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:
Am I getting the
innerText
of the<h4>
tag in the best possible way? (this could be better suited for codereview.stackoverflow.com).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;
}
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. :)
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()
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!
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);
}
}
来源:https://stackoverflow.com/questions/23225882/check-for-class-in-element-in-while-loop-in-javascript