Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial
Kristian Woods
23,414 PointsHow can I create an accordion using OOJS
I'm trying to create a function that allows you to click on an item in a group of items, and collapse and expand the height of the specific item that was clicked. However, currently, whatever item is clicked, expands and collapses all of them. I'm not sure what the best approach is.
<div class="wrapper">
<div class="myDiv" data-state="open" id="1"></div>
<div class="myDiv" data-state="open" id="2"></div>
<div class="myDiv" data-state="open" id="3"></div>
<div class="myDiv" data-state="open" id="4"></div>
</div>
class Height {
constructor(el) {
this.element = el;
}
get state(){
return $(this.element).attr('data-state');
}
set _state(newState){
$(this.element).attr('data-state',newState);
}
expand() {
$(this.element).css('height', '200px');
this._state = 'open';
}
collapse() {
$(this.element).css('height', '50px');
this._state = 'close';
}
toggle(){
if(this.state == 'open') {
this.collapse();
} else if(this.state == 'close') {
this.expand();
}
}
}
var myDiv = $('.myDiv');
var myDivInstance = new Height(myDiv);
$('body').on('click', function() {
myDivInstance.toggle();
});
2 Answers
Steven Parker
243,266 PointsRemember that a jQuery object represents a collection of elements, so one based on the "myDiv" class will affect all of the numbered elements. And the Height object represented by "myDivInstance" is built using the "myDiv" variable which references the wrapper element. I found the naming a bit confusing but the real issue is that if you want to repond to clicks on individual elements, you'll need to pass the event object through to the handler so you can work directly on the event target instead of all the elements at once.
Also, it's typical accordion behavior to expand the element clicked on, and collapse all others. If you want to expand and collapse the elements individually that's fine, but I'm not sure the term "accordion" would be a good description.
Steven Parker
243,266 PointsHere's an idea: use CSS directly to establish the heights, based on the data-state setting, and just change that in your handler:
[data-state="open"] { height: 200px; }
[data-state="close"] { height: 50px; }
$(".myDiv").on("click", function(e) {
if (e.target.dataset.state == "open") {
e.target.dataset.state = "close";
} else {
e.target.dataset.state = "open";
}
});
Kristian Woods
23,414 PointsHey, Steven! thanks for getting back to me, man. Yeah, I thought that using the event obj would be the best approach. I was initially trying to use the index value within the each loop. I'm trying to keep it as self contained as possible. But that didn't work.
$(this.element).find('.myDiv').each(function(index, element) {
// DO STUFF
});
ok, so I should do this?
$('.myDiv').on('click', function(e) {
e.target.toggle();
});
Thanks, again
Steven Parker
243,266 PointsYou're getting closer, but remember that e.target will be a standard element and not a "Height" object, so it won't have a "toggle" method.
See the comment I added to my answer for a suggested modification.
Kristian Woods
23,414 PointsKristian Woods
23,414 Pointshttps://codepen.io/Woodenchops/pen/ZwrBwB?editors=1011