...

View Full Version : js accordion help



mike182uk
03-15-2009, 02:51 AM
hey there again.

i have been having ago at writing my own accordion style script. i no there are alot of awesome frameworks out there that can already do this, but i want to try and work out what makes it tick before i use a framework.

so here goes:



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script type="text/javascript">

accordion = {

slideTime: 1,
slidePixels: 10,

slideDown:function(){
var accordionItem = document.getElementById('item1')
var currentHeight = accordionItem.offsetHeight;
if(currentHeight == 200){accordion.slideUp()};
accordionItem.style.height = currentHeight+accordion.slidePixels+'px';
accordion.slideFx = setTimeout('accordion.slideDown()',accordion.slideTime)
if(currentHeight == 190){clearTimeout(accordion.slideFx)};

},

slideUp:function(){
var accordionItem = document.getElementById('item1')
var currentHeight = accordionItem.offsetHeight;
accordionItem.style.height = currentHeight-accordion.slidePixels+'px';
accordion.slideFx = setTimeout('accordion.slideUp()',accordion.slideTime)
if(currentHeight == 20){
clearTimeout(accordion.slideFx);
accordionItem.style.height = '' //sets height to default css set height
};
}

}


</script>
<style type="text/css">
#item1 {
background-color: #F00;
height: 20px;
width: 200px;
}
#item2 {
background-color: #6F0;
height: 20px;
width: 200px;
}
#item3 {
background-color: #FF0;
height: 20px;
width: 200px;
}
#item4 {
background-color: #00F;
height: 20px;
width: 200px;
}
</style>
</head>

<body>
<div id="item1" onclick="accordion.slideDown()"></div>
<div id="item2" onclick="accordion.slideDown()"></div>
<div id="item3" onclick="accordion.slideDown()"></div>
<div id="item4" onclick="accordion.slideDown()"></div>
</body>
</html>


ok so it works how i would expect it to.

i have a few questions tho:

1. how do i make it dynamic, in the sense that whatever div you click on, that item in the accordion is shown. i thought about passing it a reference in the function call, but this does not seem to work. i think it fails at the setTimeout. but i can not understand why.

2. on the slideUp function when i use:


if(currentHeight == 20){
clearTimeout(accordion.slideFx);
accordionItem.style.height = '' //sets height to default css set height
};


i would expect the the timeout to stop when the current height equals 20. but for some reason it does not do that, and i have to tell it to revert to its original styling. why does it do this?

3. is this a ridiculous way to achieve this?

mike182uk
03-16-2009, 11:27 PM
hi there.

since my last post i had no replies. so i had another ago at this code. and ive gotten alot further than i had, but im really stuck now. :confused:

ok heres the new code:



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script type="text/javascript">

accordion = {

intervalTracker: undefined,
slidePixels: 10,
slideSpeed: 1,
slideElement: {
element: undefined,
slideStatus:'up',
maxSlideHeight: undefined,
minSlideHeight: undefined,
nextElementQueued: false,
nextQueuedElement: undefined,
},

slide:function(elementID,maxHeight,minHeight){
accordion.monitor(elementID);
this.slideElement.maxSlideHeight = maxHeight;
this.slideElement.minSlideHeight = minHeight;

if(this.slideElement.slideStatus == 'up'){
this.intervalTracker = setInterval('accordion.slideDown()',this.slideSpeed);
}

if(this.slideElement.slideStatus == 'down'){
this.intervalTracker = setInterval('accordion.slideUp()',this.slideSpeed);
}
},

slideDown:function(){
var currentHeight = this.slideElement.element.offsetHeight;
if (currentHeight == this.slideElement.maxSlideHeight){
this.slideElement.slideStatus = 'down';
clearInterval(this.intervalTracker);
}
this.slideElement.element.style.height = currentHeight+this.slidePixels+'px'
},

slideUp:function(){
var currentHeight = this.slideElement.element.offsetHeight;
if (currentHeight == this.slideElement.minSlideHeight){
this.slideElement.slideStatus = 'up';
clearInterval(this.intervalTracker);
}
this.slideElement.element.style.height = currentHeight-this.slidePixels+'px'
},

monitor:function(elementID){
if(this.slideElement.element == undefined){
this.slideElement.element = document.getElementById(elementID);
return;
}
if(this.slideElement.element.id !== elementID && this.slideElement.slideStatus == 'up'){
this.slideElement.element = document.getElementById(elementID);
return;
}
}
}


</script>
<style type="text/css">
#item1 {
background-color: #F00;
height: 20px;
width: 200px;
overflow: hidden;
}
#item2 {
background-color: #6F0;
height: 20px;
width: 200px;
}
#item3 {
background-color: #FF0;
height: 20px;
width: 200px;
}
#item4 {
background-color: #00F;
height: 20px;
width: 200px;
}
</style>
</head>

<body>
<div id="accordion">
<div id="item1" onclick="accordion.slide('item1',190,30)"></div>
<div id="item2" onclick="accordion.slide('item2',190,30)"></div>
<div id="item3" onclick="accordion.slide('item3',190,30)"></div>
<div id="item4" onclick="accordion.slide('item4',190,30)"></div>
</div>
</body>
</html>


the problem i am having is, when i open one accordion item, then with that accordion item open i click on another accordion item, i want the first accordion item to close and the second one to open.

so there is always only one accordion item open and no matter which accordion item is down, that item is then closed as the new one is opened.

any ideas?

if ive not explained myself enough just say and il try and elaborate abit better.

mike182uk
03-18-2009, 11:05 AM
has anyone got any ideas on this? :(

vwphillips
03-18-2009, 12:30 PM
I can get your code to work at all but this may help


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>

<style type="text/css">
#item1 {
background-color: #F00;
height: 20px;
width: 200px;
overflow: hidden;
}
#item2 {
background-color: #6F0;
height: 20px;
width: 200px;
}
#item3 {
background-color: #FF0;
height: 20px;
width: 200px;
}
#item4 {
background-color: #00F;
height: 20px;
width: 200px;
}
</style>
<script type="text/javascript">
/*<![CDATA[*/

function slide(id,max,min){
var obj=document.getElementById(id);
var p=obj.parentNode;
if (!obj.slideme) obj.slideme=new objSlide(obj,max,min);
if (p.lst&&p.lst!=obj.slideme){
clearTimeout(p.lst.to);
p.lst.ud=-1;
p.lst.slide();
}
clearTimeout(obj.slideme.to);
obj.slideme.ud=-obj.slideme.ud;
obj.slideme.slide();
p.lst=obj.slideme;
}

function objSlide(obj,max,min){
this.obj=obj;
this.max=max;
this.min=min;
this.ud=-1;
this.to=null;
this.height=min;
}

objSlide.prototype.slide=function(){
var oop=this;
if ((this.ud>0&&this.height<this.max)||(this.ud<0&&this.height>this.min)){
this.height+=this.ud;
this.obj.style.height=this.height+'px'
this.to=setTimeout(function(){ oop.slide(); },10);
}

}
/*]]>*/
</script></head>

<body>
<div id="accordion">
<div id="item1" onclick="slide('item1',190,30)"></div>
<div id="item2" onclick="slide('item2',190,30)"></div>
<div id="item3" onclick="slide('item3',190,30)"></div>
<div id="item4" onclick="slide('item4',190,30)"></div>
</div>

</body>
</html>

mike182uk
03-20-2009, 11:52 PM
hey vwphillips,

thanx for the reply and the script that is just what im looking for.

yeah mine only works in firefox at the mo, probs my shoddy js.

i just wanna pick your brains about the script you wrote becuase im struggling to understand what is going on. so let me explain what i think is going on then hopefully you can correct me if im wrong.

i have anotated the code line by line so hopefully it should be pretty easy to see where im talking jibberish



function slide(id,max,min){
var obj=document.getElementById(id); //get element
var p=obj.parentNode; //get element parent
if (!obj.slideme) obj.slideme=new objSlide(obj,max,min); //if obj does not have the slideme prototype, add it via creating a new objSlide object and inhert all the properties and methods from the objSlide prototype
if (p.lst&&p.lst!=obj.slideme){ //I dont undertand this bit. what is p.lst? i no it is the parent of the obj but what is lst? and why p.lst&&p.lst!=obj.slideme?
clearTimeout(p.lst.to); //clear the timeout tracked by to in p.lst
p.lst.ud=-1; //set p.lst.ud to eqaul -1
p.lst.slide(); //run this function? but why the p.lst?
}
clearTimeout(obj.slideme.to); //clear the timeout tracked by to in obj.slideme
obj.slideme.ud=-obj.slideme.ud; //I dont understand this bit.
obj.slideme.slide(); //run the this function? but why the obj.slideme?
p.lst=obj.slideme;//set p.lst to equal obj.slideMe. why?
}

function objSlide(obj,max,min){
this.obj=obj; //this obj equals this obj
this.max=max; //this max equals this max
this.min=min; //this max equals this min
this.ud=-1; //this ud equals -1. why? is there a significance in using a negative number? what is this variable for?
this.to=null; //this to equals null. what is this variable for?
this.height=min; //this height equals the min height. why?
}

objSlide.prototype.slide=function(){
var oop=this; //oop equals this. why do we have to declare this?
if ((this.ud>0&&this.height<this.max)||(this.ud<0&&this.height>this.min)){ //if this ud is greater than 0 and this height is less than this max height OR this ud is less than 0 and this height is greater than this min height... with this i dont understand what the brackets around each statement are for.
this.height+=this.ud; //this height equals this height + this.ud. i dont understand this bit. that would mean this.height+-1?
this.obj.style.height=this.height+'px' //set an inline css rule for the height of the element to equal this height
this.to=setTimeout(function(){ oop.slide(); },10); //this to is the tracker for the setTimeout. then the timeout runs the function oop.slide() every 10 milliseconds. with this i dont understand why we have to put the function declaration in the setTimeout and why we have to but oop before the .slide()
}

}



i no it may seem like a pain in the arse when you have to explain your own code, i just want to try and learn so i can apply these principles next time. i am still learning javascript.

thank-you for your patienece and your time

mike

vwphillips
03-21-2009, 11:33 AM
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>

<style type="text/css">
#item1 {
background-color: #F00;
height: 20px;
width: 200px;
overflow: hidden;
}
#item2 {
background-color: #6F0;
height: 20px;
width: 200px;
}
#item3 {
background-color: #FF0;
height: 20px;
width: 200px;
}
#item4 {
background-color: #00F;
height: 20px;
width: 200px;
}
</style>
<script type="text/javascript">
/*<![CDATA[*/

function slide(id,max,min){
var obj=document.getElementById(id); //get element
var p=obj.parentNode; //get element parent
if (!obj.slideme) obj.slideme=new objSlide(obj,max,min); //if obj does not have the slideme prototype, add it via creating a new objSlide object and inhert all the properties and methods from the objSlide prototype
if (p.lst&&p.lst!=obj.slideme){
// p.lst is the last div to be opened/closed, this div must be closed when a new div opened
//I dont undertand this bit. what is p.lst? i no it is the parent of the obj but what is lst? and why p.lst&&p.lst!=obj.slideme?
clearTimeout(p.lst.to); //clear the timeout tracked by to in p.lst
p.lst.ud=-1; //set p.lst.ud to eqaul -1 Make sure it is set to close
p.lst.slide(); //run this function? but why the p.lst? Close the div
}
clearTimeout(obj.slideme.to); //clear the timeout tracked by to in obj.slideme
obj.slideme.ud=-obj.slideme.ud; //I dont understand this bit. if ud is set to close toggle to open and if ud is set to open toggle to close
obj.slideme.slide(); //run the this function? but why the obj.slideme?
// obj.slideme is the oop object(a collection of functions) for that div, all divs have one
p.lst=obj.slideme;//set p.lst to equal obj.slideMe. why? , so the div can be closed when anther is opened
}


function objSlide(obj,max,min){
this.obj=obj; //this obj equals this obj
this.max=max; //this max equals this max
this.min=min; //this max equals this min
this.ud=-1; //this ud equals -1. why? is there a significance in using a negative number? what is this variable for?
// -1 clsed the div, +1 opens the div

this.to=null; //this to equals null. what is this variable for? This var is used for the timeout which must be cleared before calling .slide
this.height=min; //this height equals the min height. why? this if used to track the height of the div in .slide
}

objSlide.prototype.slide=function(){
var oop=this; //oop equals this. why do we have to declare this?
// so that this function can be called in the set timeout
// as it is a local variable it is unique to this instance of the function
if ((this.ud>0&&this.height<this.max)||(this.ud<0&&this.height>this.min)){ //if this ud is greater than 0 and this height is less than this max height OR this ud is less than 0 and this height is greater than this min height... with this i dont understand what the brackets around each statement are for.
this.height+=this.ud; //this height equals this height + this.ud. i dont understand this bit. that would mean this.height+-1?
// the.height(the current height) is incremented by this.ud(1 or -1)
this.obj.style.height=this.height+'px' //set an inline css rule for the height of the element to equal this height
this.to=setTimeout(function(){ oop.slide(); },10); //this to is the tracker for the setTimeout. then the timeout runs the function oop.slide() every 10 milliseconds.
// with this i dont understand why we have to put the function declaration in the setTimeout, this is the correct 'anonomus' notation for setTimeout
// and why we have to but oop before the .slide()
// It needs to know the correct .slide to call(all divs have one) oop is registered and can be used after 10ms, this will no longer exist
}

}/*]]>*/
</script></head>

<body>
<div id="accordion">
<div id="item1" onclick="slide('item1',190,30)"></div>
<div id="item2" onclick="slide('item2',190,30)"></div>
<div id="item3" onclick="slide('item3',190,30)"></div>
<div id="item4" onclick="slide('item4',190,30)"></div>
</div>

</body>
</html>

mike182uk
03-21-2009, 01:45 PM
thanx alot vwphillips thats really cleared some stuff up.

i just have one last question on this.

i have rewrote the code, just to breakdown exactly whats going on. your code is far more optomized than mine and alot better, i just want to be able to see where stuff is going wrong.

in mine i can get everything to work except when 1 div is open and another is clicked (the clicked div should close as the open div should open).



var slideRate = 5;
var slideSpeed = 1;

function slide(elementID,maxHeight,minHeight){
var obj = document.getElementById(elementID);
var accordion = obj.parentNode;
if(!obj.slideME){
obj.slideME = new slideable(obj,maxHeight,minHeight);
}
if(accordion.lastActiveObj && accordion.lastActiveObj.slideStatus == 1){
accordion.lastActiveObj.slideUp()
}
if(obj.slideME.slideStatus == 0){
obj.slideME.slideDown();
accordion.lastActiveObj = obj.slideME;
}
if(obj.slideME.slideStatus == 1){
obj.slideME.slideUp();
}
}

function slideable(obj,maxHeight,minHeight){
this.obj = obj;
this.maxHeight = maxHeight;
this.minHeight = minHeight;
this.slideStatus = 0;
this.slideTracker = null;
}

slideable.prototype.slideDown = function(){
thisObj = this;
var currentHeight = this.obj.offsetHeight;
if(currentHeight != this.maxHeight){
this.obj.style.height = currentHeight+slideRate+'px';
this.slideTracker = setTimeout(function(){ thisObj.slideDown() },slideSpeed);
}
if(currentHeight == this.maxHeight){
clearTimeout(this.slideTracker);
this.slideStatus = 1;
}
}

slideable.prototype.slideUp = function(){
thisObj = this;
var currentHeight = this.obj.offsetHeight;
if(currentHeight != this.minHeight){
this.obj.style.height = currentHeight-slideRate+'px';
this.slideTracker = setTimeout(function(){ thisObj.slideUp() },slideSpeed);
}
if(currentHeight == this.minHeight){
clearTimeout(this.slideTracker);
this.slideStatus = 0;
}
}


i have highlighted in the red the code that i believe should work but does not? is this a problem with how i have wrote the script?

i really do appreciate your time and patience in helping me with this.

vwphillips
03-21-2009, 03:16 PM
var slideRate = 5;
var slideSpeed = 1;

function slide(elementID,maxHeight,minHeight){
var obj = document.getElementById(elementID);
var accordion = obj.parentNode;
if(!obj.slideME){
obj.slideME = new slideable(obj,maxHeight,minHeight);
}
if(accordion.lastActiveObj &&accordion.lastActiveObj!=obj.slideME&& accordion.lastActiveObj.slideStatus == 1){
accordion.lastActiveObj.slideUp()
}
if(obj.slideME.slideStatus == 0){
obj.slideME.slideDown();
accordion.lastActiveObj = obj.slideME;
}
if(obj.slideME.slideStatus == 1){
obj.slideME.slideUp();
}
}

function slideable(obj,maxHeight,minHeight){
this.obj = obj;
this.maxHeight = maxHeight;
this.minHeight = minHeight;
this.slideStatus = 0;
this.slideTracker = null;
}

slideable.prototype.slideDown = function(){
var thisObj = this;
var currentHeight = this.obj.offsetHeight;
if(currentHeight != this.maxHeight){
this.obj.style.height = currentHeight+slideRate+'px';
this.slideTracker = setTimeout(function(){ thisObj.slideDown() },slideSpeed);
}
if(currentHeight == this.maxHeight){
clearTimeout(this.slideTracker);
this.slideStatus = 1;
}
}

slideable.prototype.slideUp = function(){
thisObj = this;
var currentHeight = this.obj.offsetHeight;
if(currentHeight != this.minHeight){
this.obj.style.height = currentHeight-slideRate+'px';
this.slideTracker = setTimeout(function(){ thisObj.slideUp() },slideSpeed);
}
if(currentHeight == this.minHeight){
clearTimeout(this.slideTracker);
this.slideStatus = 0;
}
}


also your code does not allow toggleing while expanding or collapseing

mike182uk
03-21-2009, 05:13 PM
thanks alot vwphillips thatas awesome.

yeh as well as the toggoling, also the animation on mine is not too smooth. it judders quite alot.

but your script works exactly how i want.

thanks alot for all your help and time (and paitenece) on this.
it is most appreciated

vwphillips
03-22-2009, 02:46 PM
One problem with the script is that it is increment based rather than time based.
Another is the lack of flexibility.

May be worth a look at (about 2K of code) for most animations.

http://www.vicsjavascripts.org.uk/AnimatorBasic/AnimatorBasic.htm



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum