Jump to content

Know whether I am on the child element, not the parent, with the same function


joe92

Recommended Posts

Hi,

 

I am writing a function which will apply an active class to a div that has been clicked. I am running into a problem in that the function that is called on all the elements involved doesn't know how to differentiate between the elements, and will therefore jump to the highest element with the call. If that's clear enough?

 

The function is written to first remove the active class from whichever element it used to be on, and then apply it to our current element.

 

Here is the javascript function:

function setActiveThis(el){
var container = document.getElementById('activeContainer');
var containerEls = container.getElementsByTagName('*');
var theClass = '';
var newClass = '';
for(var i=0;i<containerEls.length;i++)
	{
			/*get the class of the current element*/
		theClass = containerEls[i].className;
			/*check the class is not blank*/
		if(theClass != '')
			{
					/*check if this element is the active one*/
				if(theClass.match(/active/))
					{
							/*remove the active class from it*/
						newClass = theClass.replace(/\s?active/, '');
						containerEls[i].className = newClass;
							/*since there is only ever one active class break out of the loop*/
						i = containerEls.length;
					}
			}
	}
var elClass = el.className;
elClass += ' active';
el.className = elClass;
}

And here is the HTML that I am testing it with:

<div id="activeContainer">
<div onclick="setActiveThis(this);">
	Content1
	<div onclick="setActiveThis(this);">
		Content2
		<div onclick="setActiveThis(this);">
			Content3
			<div onclick="setActiveThis(this);">
				Testing
			</div>
		</div>
	</div>
</div>
<div onclick="setActiveThis(this);">
	I work because there are no higher elements with the setActiveThis function around me
</div>
</div>

 

What I need is for when I click on a div, for example the word testing, the active class be applied to ONLY the div which directly contains it. Currently, it is applying it to the highest element that wraps around it with the setActiveThis function, in this example applying it to the div with content1. How can I get it to apply the active class to the 'testing' div only?

 

If this isn't clear enough, please say so and I will try to reword my problem. Any and all help is appreciated!

 

Cheers,

Joe

Link to comment
Share on other sites

You have two problems:

 

1. The child elements are INSIDE the parent elements. So, when you click on the child you are also clicking on the parent. If you put an alert in the function you will see it popup multiple times based upon which child element you select.

2. The child elements will inherit the styles of the parent elements.

 

The easy fix is to not have nested divs.

Link to comment
Share on other sites

You have two problems:

 

1. The child elements are INSIDE the parent elements. So, when you click on the child you are also clicking on the parent. If you put an alert in the function you will see it popup multiple times based upon which child element you select.

2. The child elements will inherit the styles of the parent elements.

 

The easy fix is to not have nested divs.

 

Problem 2 is actually a desired result - when they click the parent it highlights them all by carrying the style through and when they click the child it only highlights the child. It's problem 1 that I'm trying to get around. I just don't know how yet.

 

 

You can just stop the event propagation.

 

Thank you for pointing me in the right direction. Google's given me this tutorial, which describes my exact problem in the first sentence, from a quick search so I'll see what I can do. I wasn't even aware of event propagation so I might be back soon with another question ;D Looks interesting though, thanks again!

Link to comment
Share on other sites

OK, after a morning of reading and learning new JavaScript functions and tricks I have come up with the following to try and fix it.

function cancelBubble(e) {
var evt = e || window.event;
	/*ff/chrome etc. route*/
if (evt.stopPropagation)
	{
		evt.stopPropagation();
	}
	/*ie route*/
else{
		evt.cancelBubble = true;
	}
}
function setActiveThis(tg){
	/*add custom event listener to the element to prevent event propagation*/
if(tg && tg.addEventListener)
	{
		tg.addEventListener('click', cancelBubble, false);
	}
else if(tg && tg.attachEvent)
	{
		tg.attachEvent('onclick', cancelBubble);
	}

	/*start event*/
var container = document.getElementById('activeContainer');
var containerEls = container.getElementsByTagName('*');
var theClass = '';
var newClass = '';
for(var i=0;i<containerEls.length;i++)
	{
			/*get the class of the current element*/
		theClass = containerEls[i].className;
			/*check the class is not blank*/
		if(theClass != '')
			{
					/*check if this element is the active one*/
				if(theClass.match(/active/))
					{
							/*remove the active class from it*/
						newClass = theClass.replace(/\s?active/, '');
						containerEls[i].className = newClass;
							/*since there is only ever one active class break out of the loop*/
						i = containerEls.length;
					}
			}
	}
var tgClass = tg.className;
tgClass += ' active';
tg.className = tgClass;
}

 

This works perfectly, absolutely what I needed. However, it only works after the first click. I.e. the first click still applies the active class to the highest element with the event attached to it, but all subsequent clicks go in their intended positions. Any idea why that's happening and how I can fix it? I'm guessing that it may be to do with the timing of when I add the event listeners?

 

Thanks for all you help. I've nearly got this one sorted,

Joe

Link to comment
Share on other sites

And it was entirely to do with the timing. To get round it, I've attached a class of stopPropagation to all the elements that have the setActiveThis function attached to them. Then on window.load I run a function that loop's through all elements with this class and attaches the needed event listener to stop event propagation.

 

Problem solved and I've learnt a lot! Thank you,

Joe

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.