Scott
Scott

Reputation: 1310

JavaScript Elements

I need help with the following:

I have a page with h3-s and paragraphs and I want all the paragraphs to initially be hidden.

If a h3 is clicked, the script will loop through the tags below it, showing the paragraph tags, if it comes to another h3 tag it should break out the loop.

I have no control over the html output so I can't nest the tags or give any of the h3-s ids. The code below is all i have to play with.

E.g. If H3 Title2 is clicked, then Title 2 Para 1 and Title 2 Para 2 are shown, if H3 Title2 is clicked again then Title 2 Para 1 and Title 2 Para 2 are hidden.

<h3>H3 Title1</h3>
<p>Title 1 Para 1</p>
<p>Title 1 Para 2</p>
<p>Title 1 Para 3</p>
<p>Title 1 Para 4</p>


<h3>H3 Title2</h3>
<p>Title 2 Para 1</p>
<p>Title 2 Para 2</p>


<h3>H3 Title3</h3>
<p>Title 3 Para 1</p>
<p>Title 3 Para 2</p>


<h3>H3 Title4</h3>
<p>Title 4 Para 1</p>
<p>Title 4 Para 2</p>
<p>Title 4 Para 3</p>

No jQuery please

Upvotes: 0

Views: 119

Answers (3)

Felix Kling
Felix Kling

Reputation: 816262

I completely agree with xqwzts' answer: Get a reference to the clicked H3 element, iterate over the following nodes and inspect them (type and name).

Here is another, maybe easier to read solution:

// the event handler we are going to use
var handler = function() {
    // `this` refers to the clicked element
    var node = this.nextSibling;
    // iterate over all following nodes
    for(; node ; node = node.nextSibling) {
        if(node.nodeName === 'P') {
            // if it is a p element, toggle the visibility
            node.style.display = node.style.display === 'block' ? '' : 'block';
        }
        else if(node.nodeName === 'H3') { // or node.nodeType === 1
            break; // if it is a H3 element (or an element but not P), stop
        }
    }
};

// get all h3 elements
var h3s = document.getElementsByTagName('h3');

// assign a click event handler to all of them
for(var i = 0, l = h3s.length; i < l; i++) {
    h3s[i].onclick = handler;
}

DEMO

There are various ways to bind event handlers, all of which are well explained at quirksmode.org.

Reference: getElementsByTagName, Node#nodeName, Node#nodeType, Element#style

Upvotes: 0

Paul S.
Paul S.

Reputation: 66304

Something like..

var pHide = function () {
    var ps = document.getElementsByTagName('p'), i = ps.length;
    while(i-->0) ps[i].style.display = 'none';
},
toggleDisplay = function (elm) {
    elm.style.display = elm.style.display === 'none' ? 'block' : 'none';
},
nextNode = function (elm) { // can't assume built in?
    var e = elm;
    while( e = e.nextSibling ) if ( e.tagName !== undefined ) break;
    return e;
},
addActions = function () {
    var hs = document.getElementsByTagName('h3'), i = hs.length;
    while(i-->0) hs[i].addEventListener('click',function () {
        var elm = this;
        while( (elm = nextNode(elm)) && elm.tagName.toLowerCase() != 'h3') if(elm.tagName.toLowerCase() == 'p') toggleDisplay(elm);
    }, false);

};
pHide();
addActions();​

Example fiddle

Upvotes: 1

xqwzts
xqwzts

Reputation: 3538

Take a look at getElementsByTagName to get all the H3s on your page, you want to attach a click() handler to those.

In your onclick you loop over all the next elements until you get to an H3 and break out of the loop. Take a look at nextElementSibling for getting the elements after the H3.

For showing/hiding either set a css class or directly change the element's style toggling between display:block and display:none.

Upvotes: 2

Related Questions