Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 10 of 10
  1. #1
    Regular Coder
    Join Date
    May 2008
    Posts
    135
    Thanks
    13
    Thanked 10 Times in 10 Posts

    js accordion help

    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:

    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 = {
    	
    	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:
    Code:
    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?

  • #2
    Regular Coder
    Join Date
    May 2008
    Posts
    135
    Thanks
    13
    Thanked 10 Times in 10 Posts
    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.

    ok heres the new code:

    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.

  • #3
    Regular Coder
    Join Date
    May 2008
    Posts
    135
    Thanks
    13
    Thanked 10 Times in 10 Posts
    has anyone got any ideas on this?

  • #4
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,503
    Thanks
    3
    Thanked 500 Times in 487 Posts
    I can get your code to work at all but this may help

    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>
    
    <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>
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/

  • #5
    Regular Coder
    Join Date
    May 2008
    Posts
    135
    Thanks
    13
    Thanked 10 Times in 10 Posts
    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

    Code:
    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

  • #6
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,503
    Thanks
    3
    Thanked 500 Times in 487 Posts
    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>
    
    <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>
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/

  • #7
    Regular Coder
    Join Date
    May 2008
    Posts
    135
    Thanks
    13
    Thanked 10 Times in 10 Posts
    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).

    Code:
    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.

  • #8
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,503
    Thanks
    3
    Thanked 500 Times in 487 Posts
    Code:
    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
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/

  • Users who have thanked vwphillips for this post:

    mike182uk (03-21-2009)

  • #9
    Regular Coder
    Join Date
    May 2008
    Posts
    135
    Thanks
    13
    Thanked 10 Times in 10 Posts
    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

  • #10
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,503
    Thanks
    3
    Thanked 500 Times in 487 Posts
    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/An...matorBasic.htm
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •