http://www.daniweb.com/blogs/showentry.php?entryid=655

In reference to the script made by ben at the above address. I'm trying to decipher how to create a toggle where as, only one "slideblock" can be open at a time. When you try to make one visible, all others "slidein".

Anyone have any ideas? Javascript has always been a pain in my rear-end.

Recommended Answers

All 17 Replies

I could probably make something that toggles, I just need to know exactly what parts of the script make it slide in and slide out. It's not apparent, even with the comments. I'm a php programmer. Javascript is so different.

I think I know what I was doing wrong. I was trying to modify the "toggle" function, when what I really should do, is create a new function that USES the toggle, to toggle the correct elements...

Hi i was wondering how hard it would be to make the div's start closed?
I tried to add a script after the div so that it would run as soon as it was loaded but I couldn't work out what variable I needed to pass to the toggle() function.

Thanks

Hi i was wondering how hard it would be to make the div's start closed?
I tried to add a script after the div so that it would run as soon as it was loaded but I couldn't work out what variable I needed to pass to the toggle() function.

Thanks

Ya ther eis a way to do that, it's really easy too.

display: none;

you can't put that in an external css for that div, it has to be part of the style attr of the div. Example:

<div class="slide" style="display: none;">
some text here
</div>

that should force it to not be displayed when the page loads. Otherwise, change it to display: block;

Good idea, only problem is it doesn't work.
Something in the script makes it appear still I think. In Firefox after adding that, it still appears as normal then when you hide and then show it is only a couple of pixels high and you can't see the div anymore. In IE just works like it did before although it does hide until I let IE run the activex on the site then it acts like it normally does.

Bother

Any other suggestions?

Oh man now I feel stupid. There is one line already there that needs editing.

divs[i].style.display = "block";

just needs to be changed to

divs[i].style.display = "block";

And they all hide. Sorry I didn't find that sooner. Now I just need to work out how to have two of these running side by side so one is up and one is down.

Now I just need to work out how to have two of these running side by side so one is up and one is down.

Well i have worked out that if you copy that line

divs[i].style.display = "none";

and replace i with a number you can overwrite the default setting for that numbered div. So if you use that line followed by this one

divs[1].style.display = "block";

All the divs will hide when the page loads, except for the second one. Just need to change the link text too.

Now my only other problem is that I want one link to toggle two of these (i am doing the accordian effect) The only problem is I still don't know the value of this that is being passed to toggle. I can put in another function that activates when the link is clicked I just can't figure out how to make this trip the toggle in the second div.

I hope someone can help, this is almost perfect now for what I need.

Thanks

Think I have worked out the solution, rewrite the script, so that it uses class names rather than having bits of the script, gather data based on the location of the trigger. By removing this, it will be easy to specify which div start opened and closed and also which ones toggle from which length.

So now the question is can anyone help me with this?
I will have a go but it will take me a week because the script is just a little bit too complicated for me to follow. Hope someone can help thanks.

Use one variable to decide which one is out.

Values:
0 = all in
1 = first one out
2 = second one out
3 = third one out
etc.

Keep a previous value variable to tell it which one to slide in.

I think I understand what you mean but I am not sure this will work for me. I think I have sorted most of it now though. I have worked out how to control which div is being targeted.

<html>
<head>
<title>Sliding divs - Digg Style</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
<style type="text/css">
* { font-family: Verdana, Arial, Helvetica, sans-serif; color: #000; margin: 0px; padding: 0px; }
body { padding: 20px; }

.slidey { margin-bottom: 10px; }
.slidey .title { background-color: #CCC; } 
/* the only noteworthy thing here is the overflow is hidden, 
it's really a sleight-of-hand kind of thing, we're playing
with the height and that makes it 'slide' */
.slidey .slideblock { overflow: hidden; background-color: #DDD; padding: 2px; font-size: 10px; } 
</style>
<script type="text/javascript">

// our global vars
var heightnow;
var targetheight;
var block;
var slideinterval;
var divheights = new Array();
//these two added for accordian function
var go2
var q

// the delay between the slide in/out, and a little inertia
var inertiabase = 1;
var inertiainc = 1;
var slideintervalinc = 50;
var inertiabaseoriginal = inertiabase;

window.onload = function()
{
	// detect whether the user has ie or not, how we get the height is different 
	var useragent = navigator.userAgent.toLowerCase();
	var ie = ((useragent.indexOf('msie') != -1) && (useragent.indexOf('opera') == -1) && (useragent.indexOf('webtv') == -1));
	var divs = getElementsByClassName(document, "div", "slideblock");

	for(var i=0; i<divs.length; i++)
	{
		// get the original height
		var baseheight = (ie) ? divs[i].offsetHeight + "px" : document.defaultView.getComputedStyle(divs[i], null).getPropertyValue('height', null);

		// explicitly display it (optional, you could use cookies to toggle whether to display it or not)
		divs[i].style.display = "none";
        divs[0].style.display = "block";

		// "save" our div height, because once it's display is set to none we can't get the original height again
		var d = new div();
		d.el = divs[i];
		d.ht = baseheight.substring(0, baseheight.indexOf("p"));

		// store our saved versoin
		divheights[i] = d;		
	}
}

// this is one of our divs, it just has a DOM reference to the element and the original height
function div(_el, _ht)
{
	this.el = _el;
	this.ht = _ht;
}

function toggle(t)
{
//added by stretch to allow div id to be used instead of 'this'
    t=document.getElementById(t)
	// reset our inertia base and interval
	inertiabase = inertiabaseoriginal;
	clearInterval(slideinterval);

	// get our block
	block = t.parentNode.nextSibling;

	// for mozilla, it doesn't like whitespace between elements
	if(block.className == undefined)
		block = t.parentNode.nextSibling.nextSibling;

	if(block.style.display == "none")
	{
		// link text
		t.innerHTML = "Hide";

		block.style.display = "block";
		block.style.height = "1px";

		// our goal and current height
		targetheight = divheight(block);
		heightnow = 1;

		// our interval
		slideinterval = setInterval(slideout, slideintervalinc);
	}
	else
	{
		// linkstext
		t.innerHTML = "Show";

		// our goal and current height
		targetheight = 1;
		heightnow = divheight(block);

		// our interval
		slideinterval = setInterval(slidein, slideintervalinc);
	}
}


// this is our slidein function the interval uses, it keeps subtracting
// from the height till it's 1px then it hides it
function slidein()
{
	if(heightnow > targetheight)
	{
		// reduce the height by intertiabase * inertiainc
		heightnow -= inertiabase;

		// increase the intertiabase by the amount to keep it changing
		inertiabase += inertiainc;

		// it's possible to exceed the height we want so we use a ternary - (condition) ? when true : when false;
		block.style.height = (heightnow > 1) ? heightnow + "px" : targetheight + "px";
	}
	else
	{
		// finished, so hide the div properly and kill the interval
		clearInterval(slideinterval);
		block.style.display = "none"; 
//added by stretch to toggle second part
       part2()
    }
}
    

// this is the function our slideout interval uses, it keeps adding
// to the height till it's fully displayed
function slideout()
{
	if(heightnow < targetheight)
	{
		// increases the height by the inertia stuff
		heightnow += inertiabase;

		// increase the inertia stuff
		inertiabase += inertiainc;

		// it's possible to exceed the height we want so we use a ternary - (condition) ? when true : when false;
		block.style.height = (heightnow < targetheight) ? heightnow + "px" : targetheight + "px";
		
	}
	else
	{
		// finished, so make sure the height is what it's meant to be (inertia can make it off a little)
		// then kill the interval
		clearInterval(slideinterval);
		block.style.height = targetheight + "px";
//added by stretch to toggle second part
                part2()
	}
}


// returns the height of the div from our array of such things
function divheight(d)
{
	for(var i=0; i<divheights.length; i++)
	{
		if(divheights[i].el == d)
		{
			return divheights[i].ht;
		}
	}
}

/*
	the getElementsByClassName function I pilfered from this guy.  It's
	a useful function that'll return any/all tags with a specific css class.

		Written by Jonathan Snook, http://www.snook.ca/jonathan
		Add-ons by Robert Nyman, http://www.robertnyman.com
*/
function getElementsByClassName(oElm, strTagName, strClassName)
{
	// first it gets all of the specified tags
    var arrElements = (strTagName == "*" && document.all) ? document.all : oElm.getElementsByTagName(strTagName);
    
	// then it sets up an array that'll hold the results
	var arrReturnElements = new Array();

	// some regex stuff you don't need to worry about
    strClassName = strClassName.replace(/\-/g, "\\-");

    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
    var oElement;

	// now it iterates through the elements it grabbed above
    for(var i=0; i<arrElements.length; i++)
	{
        oElement = arrElements[i];

		// if the class matches what we're looking for it ads to the results array
        if(oRegExp.test(oElement.className))
		{
            arrReturnElements.push(oElement);
        }   
    }

	// then it kicks the results back to us
    return (arrReturnElements)
}
//the following by stretch for accordian effect see second link for how to trigger it
function part1(div1,div2)
    {
    q=0
    go2=div2
    toggle(div1)
    }
function part2()
        {
        if (q==0)
            {
            toggle(go2)
            q++
            }
        }    
    
</script>
<noscript>
</noscript>
</head>
<body>
	<div class="slidey">
		<div class="title">
			<a href="#" onclick="toggle('blue');" id="blue">Hide</a>
		</div>
		<div class="slideblock">
			<p>The contents of the sliding block!</p>
			<p>The contents of the sliding block!</p>
			<p>The contents of the sliding block!</p>
			<p>The contents of the sliding block!</p>
		</div>
	</div>
	<div class="slidey">
		<div class="title">
            <a href="#" onclick="part1('blue','red');" id="red">Show</a>
		</div>
		<div class="slideblock">
			<p>The contents of the sliding block!</p>
		</div>
	</div>
</body>
</html>

There are is only two problems.
One is I can't toggle both at once, it has to be one then the other, which is a shame. I was going to duplicate the code but it was too hard to change all the variable names correctly
The second is being resigned for now to having one activating after the other, is that I haven't figured out how to make it target the open one first, instead it currently just targets whichever one is called first. I will keep working on that but am not sure if I will succeed.
The last thin which I plan to do is use an array so that the link text can be changed depending on what div is being targeted at the time, so your links can be relating to the div contents like show weather or what ever is in the div.

Hope this is useful to someone else and if anyone has some suggestions for improvements or to help with the remaining issues that would be appreciated.

Thanks all

The computer can't move mope than one piece at a time. But if you alternately move one piece a little, and then move the other one a little, it looks like both are moving at the same time.

Yeah I can see how that would work, although I am not sure I understand all of the script well enough to acheive that, the way it refers to the divs is far more complicated than it should be. I have however added quite a bit of code, so that the correct div gets triggered first. Maybe if I have a bit of time I will try and simplify it.

Thanks

Hi all, I ended up writing some new code from scratch myself, its taken a little while now but it works pretty much exactly the way I want. Because everything is based on id's, a link can target multiple divs and it can change the text in multiple links. The only downside is that it isn't very fast and I haven't got to fixing that yet but as there are other more important issue on the site I am building I probably wont, the other thing is triggering the same link halfway through works fine, the slide reverses where it is, but triggering another link stops whichever slide is occuring. Anyway below is the code, although I do usually keep the script in an external file.

<html>
<head>
<title>
Slide
</title>
<script type='text/javascript'>
var divh = new Array()
var divch = new Array()
var divoh = new Array()
var movea
var moveb
var repeat
var speed
speed=1

function hide(div)
    {
    divh[div]=document.getElementById(div).offsetHeight
    document.getElementById(div).style.display="none"
    }

function toggle(parta,partb,link,linktext1,linktext2)
    {
    movea=parta    
    if(divh[movea]==undefined)
        {
        divh[movea]=document.getElementById(movea).offsetHeight
        }
    if(divoh[movea]==undefined && document.getElementById(movea).style.display!="none")
        {
        divch[movea]=divh[movea]
        divoh[movea]=divch[movea]-1
        }
    if(divoh[movea]==undefined && document.getElementById(movea).style.display=="none")
        {
        divch[movea]=0
        divoh[movea]=1
        }
    
    if(partb!='')
        {
        moveb=partb
        if(divh[moveb]==undefined)
            {
            divh[moveb]=document.getElementById(moveb).offsetHeight
            }
        if(divoh[moveb]==undefined)
            {
            divch[moveb]=divh[moveb]
            divoh[moveb]=divch[moveb]-1
            }
        }
    
    if(divch[movea]>divoh[movea] && moveb==undefined)
        {
        clearInterval(repeat)
        repeat=setInterval('slideina()',speed)
        }
    if(divch[movea]<divoh[movea] && moveb==undefined)
        {
        clearInterval(repeat)
        repeat=setInterval('slideouta()',speed)
        }
    if(divch[movea]>divoh[movea] && divch[moveb]>divoh[moveb])
        {
        clearInterval(repeat)
        repeat=setInterval('slideina()',speed)
        }
    if(divch[movea]<divoh[movea] && divch[moveb]<divoh[moveb])
        {
        clearInterval(repeat)
        repeat=setInterval('slideouta()',speed)
        }
    if(divch[movea]>divoh[movea] && divch[moveb]<divoh[moveb])
        {
        clearInterval(repeat)
        repeat=setInterval('slideinb()',speed)
        }
    if(divch[movea]<divoh[movea] && divch[moveb]>divoh[moveb])
        {
        clearInterval(repeat)
        repeat=setInterval('slideoutb()',speed)
        }
    if(document.getElementById(link).innerHTML==linktext1)
        {
        document.getElementById(link).innerHTML=linktext2
        }
    else
        {
        document.getElementById(link).innerHTML=linktext1
        }
    }

function slideina()
    {
    if(movea!=undefined)
        {
        if(divch[movea]!=1)
            {
            divoh[movea]=divch[movea]
            divch[movea]=divch[movea]-1
            document.getElementById(movea).style.height=divch[movea]
            }
        else
            {
            document.getElementById(movea).style.display="none"
            }
        }
    if(moveb!=undefined)
        {
        if(divch[moveb]!=1)
            {
            divoh[moveb]=divch[moveb]
            divch[moveb]=divch[moveb]-1
            document.getElementById(moveb).style.height=divch[moveb]
            }
        else
            {
            document.getElementById(moveb).style.display="none"
            }
        }
    if(divch[movea]==1 && divch[moveb]==1)
        {
        document.getElementById(movea).style.display="none"
        document.getElementById(moveb).style.display="none"
        clearInterval(repeat)
        movea=undefined
        moveb=undefined
        }
    }
function slideouta()
    {
    if(movea!=undefined)
        {
        document.getElementById(movea).style.display="block"
        if(divch[movea]!=divh[movea])
            {
            divoh[movea]=divch[movea]
            divch[movea]=divch[movea]+1
            document.getElementById(movea).style.height=divch[movea]
            }
        }
    if(moveb!=undefined)
        {
        document.getElementById(moveb).style.display="block"
        if(divch[moveb]!=divh[moveb])
            {
            divoh[moveb]=divch[moveb]
            divch[moveb]=divch[moveb]+1
            document.getElementById(moveb).style.height=divch[moveb]
            }
        }
    if(divch[movea]==divh[movea] && divch[moveb]==divh[moveb])
        {
        clearInterval(repeat)
        movea=undefined
        moveb=undefined
        }
    }
function slideinb()
    {
    if(movea!=undefined)
        {
        if(divch[movea]!=1)
            {
            divoh[movea]=divch[movea]
            divch[movea]=divch[movea]-1
            document.getElementById(movea).style.height=divch[movea]
            }
        else
            {
            document.getElementById(movea).style.display="none"
            }
        }
    if(moveb!=undefined)
        {
        document.getElementById(moveb).style.display="block"
        if(divch[moveb]!=divh[moveb])
            {
            divoh[moveb]=divch[moveb]
            divch[moveb]=divch[moveb]+1
            document.getElementById(moveb).style.height=divch[moveb]
            }
        }
    if(divch[movea]==1 && divch[moveb]==divh[moveb])
        {
        document.getElementById(movea).style.display="none"
        
        clearInterval(repeat)
        movea=undefined
        moveb=undefined
        }
    }
function slideoutb()
    {
    if(movea!=undefined)
        {
        document.getElementById(movea).style.display="block"
        if(divch[movea]!=divh[movea])
            {
            divoh[movea]=divch[movea]
            divch[movea]=divch[movea]+1
            document.getElementById(movea).style.height=divch[movea]
            }
        }
    
    if(moveb!=undefined)
        {
        if(divch[moveb]!=1)
            {
            divoh[moveb]=divch[moveb]
            divch[moveb]=divch[moveb]-1
            document.getElementById(moveb).style.height=divch[moveb]
            }
        else
            {
            document.getElementById(moveb).style.display="none"
            }
        }
    if(divch[movea]==divh[movea] && divch[moveb]==1)
        {
        document.getElementById(moveb).style.display="none"
        clearInterval(repeat)
        movea=undefined
        moveb=undefined
        }
    }
</script>
</head>
<body>
<p>
<a href="javascript: toggle('divnamex','divnamey','triggerboth','These change','and back to something');" id="triggerboth">Slide Both</a>
<a href="javascript: toggle('divnamex','','triggerx','another change','and back');" id="triggerx">Slide Div X</a>
<a href="javascript: toggle('divnamey','','triggery','changes link id','back');" id="triggery">Slide Div Y</a>
<div id="divnamex" style="background: green; overflow: hidden;">
Div X
<br><br>
This is content in here.
</div>
<div id="divnamey" style="background: steelblue; overflow: hidden;">
Div Y
<br><br>
More Stuff here
<br>
This div is a bit bigger to show the accordian effect on unequal size divs.
</div>
</p>
<p>
<a href="javascript: toggle('divnamex2','divnamey2','triggerboth2','These change','and back to something');" id="triggerboth2">Slide Both</a>
<a href="javascript: toggle('divnamex2','','triggerx2','another change','and back');" id="triggerx2">Slide Div X</a>
<a href="javascript: toggle('divnamey2','','triggery2','changes link id','back');" id="triggery2">Slide Div Y</a>
<div id="divnamex2" style="background: green; overflow: hidden;">
Div X
<br><br>
This is content in here.
</div>
<div id="divnamey2" style="background: steelblue; overflow: hidden;">
Div Y
<br><br>
More Stuff here
<br>
This div is a bit bigger to show the accordian effect on unequal size divs.
</div>
<script type='text/javascript'>
hide('divnamex2')
</script>
</p>
</body>
</html>
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.