Skip to content

Instantly share code, notes, and snippets.

@shduff
Created April 11, 2016 16:49
Show Gist options
  • Save shduff/72d5c6d8e4753ab244f68c63a96935bf to your computer and use it in GitHub Desktop.
Save shduff/72d5c6d8e4753ab244f68c63a96935bf to your computer and use it in GitHub Desktop.
using javascript to hide and show different elements from a nested lists, on click
<!DOCTYPE html>
<html>
<head>
<!-- <script src="https://code.jquery.com/jquery-1.12.3.min.js"></script> -->
<style>
body {
margin: 0;
padding: 0;
}
#menu {
position: absolute;
background-color: #D3D3D3;
width: 100%;
height: auto;
margin: auto;
}
.hide {
display: none;
}
/* shaunalynn: Rather than having two different classes, I'd make use of
1.) the fact that elements' default display attribute is block, and
2.) the classList.toggle function (https://developer.mozilla.org/en-US/docs/Web/API/Element/classList)
.shown {
display: block;
} */
</style>
</head>
<body>
<header>
<h1>My App</h1>
</header>
<div id="menu">
<ul id="Books">
</ul>
</div>
</div>
<script>
var bookData = {
'id11111': {
'book1': {
"chapter1": [
"text from book 1 chapter 1 page 1",
"text from book 1 chapter 1 page 2",
"text from book 1 chapter 1 page 3"
],
"chapter2": [
"text from book 1 chapter 2 page 1",
"text from book 1 chapter 2 page 2"
]
}
},
'id22222': {
'book2': {
"chapter1": [
"text from book 2 chapter 1 page 1",
"text from book 2 chapter 1 page 2",
"text from book 2 chapter 1 page 3"
],
"chapter2": [
"text from book 2 chapter 2 page 1",
"text from book 2 chapter 2 page 2"
],
"chapter3": [
"text from book 2 chapter 3 page 1",
"text from book 2 chapter 3 page 2",
"text from book 2 chapter 3 page 3"
],
"chapter4": [
"text from book 2 chapter 4 page 1"
]
}
},
'id33333': {
'book3': {
"chapter1": [
"text from book 3 chapter 1 page 1",
"text from book 3 chapter 1 page 2",
"text from book 3 chapter 1 page 3"
]
}
},
'id44444': {
'book4': {
"chapter1": [
"text from book 4 chapter 1 page 1",
"text from book 4 chapter 1 page 2",
"text from book 4 chapter 1 page 3"
],
"chapter2": [
"text from book 4 chapter 2 page 1",
"text from book 4 chapter 2 page 2"
],
"chapter3": [
"text from book 4 chapter 3 page 1",
"text from book 4 chapter 3 page 2",
"text from book 4 chapter 3 page 3"
],
"chapter4": [
"text from book 4 chapter 4 page 1"
],
"chapter5": [
"text from book 4 chapter 5 page 1",
"text from book 4 chapter 5 page 2",
"text from book 4 chapter 5 page 3",
"text from book 4 chapter 5 page 4",
"text from book 4 chapter 5 page 5"
]
}
},
};
// shaunalynn: Laura, I've commented out a bunch of your code. From what I could tell, you weren't actually using the "showDiv" function or onclick eventListeners. I hope this was correct!
for (var key in bookData) {
var bookItem = document.createElement('li'); //create a list
for (var title in bookData[key]) { // for the keys in book data make an element called 'title'
var titleDiv = document.createElement('div'); // create a div to store book titles
titleDiv.setAttribute("class", "titles"); // set class // shaunalynn: Removed "shown" class.
// var onClickCommand = "showDiv()" // have a command that hides 'chapterItem' on click
// titleDiv.onclick = onClickCommand;
// console.log("onclick command added");
// console.log(titleDiv.onclick);
// titleDiv.setAttribute("onclick", "showDiv()");
titleDiv.innerText = title; // put whatever keys you got from 'title' into the div created
// shaunalynn: Because you are already doing the work of looping through this complicated dictionary, I would suggest adding event listeners to elements as you go, rather than introducing the complexity of jQuery. In this case, I actually think you need to write less code in Javascript.
titleDiv.addEventListener('click', function(event) {
event.target.nextSibling.classList.toggle('hide');
// shaunalynn: This eventListener toggles the "hide" class (e.g. attaches or detaches, depending on the current state) on the "chapters" list below the clicked element (e.g. "event.target"). It finds the chapters list by looking at the "siblings" of the clicked element, hence "nextSibling".
});
bookItem.appendChild(titleDiv); // get the child of bookItem 'titleDiv'
var chapterList = document.createElement('ul'); //make a list called 'chapterList' // shaunalynn: I changed this element from a "div" to a "ul" for clarity/consistency.
chapterList.setAttribute('class', 'chapters hide'); // shaunalynn: I moved the "chapters" class to be on the containing "ul" element so we'd be able to show/hide the whole list in one go.
bookItem.appendChild(chapterList); //get child 'chapterList' and put list in it.
document.getElementById("Books").appendChild(bookItem);
for (var chapter in bookData[key][title]) {
var chapterItem = document.createElement('li');
// chapterItem.setAttribute("class", "hide chapters"); // shaunalynn: Moved to "ul" as described above.
chapterItem.innerText = chapter; //The title is the name of the property in the array
chapterItem.addEventListener('click', function(event) {
event.target.children[0].classList.toggle('hide');
// shaunalynn: This eventListener does a very similar one to the last, but looks a little different because the structure of your nested lists is a little different at this point. Here, when we want to get the list of "text" elements, we have to grab the "children" of the clicked element, rather than the siblings, simply because of the structure of the lists you've created.
});
chapterList.appendChild(chapterItem);
var textList = document.createElement('ul');
textList.setAttribute("class", "text hide");
chapterItem.appendChild(textList);
var chapterTexts = bookData[key][title][chapter];
chapterTexts.forEach(function(text) {
var textElement = document.createElement('li');
textElement.innerText = text;
textList.appendChild(textElement);
});
};
};
};
// trying out jQuery function that's buggy but that does open up only one book
// $(document).ready(function () {
// $('ul#Books > li').click(function () {
// selfActive = $(this).hasClass("shown")?true:false;
// $(".hide").removeClass("hide").find("ul").slideUp();
// if (!selfActive){
// $(this).addClass("shown").find("ul").slideDown();
// }
// });
// });
// function showDiv() {
// var showDiv = document.getElementsByClassName('text');
// for (var i = 0; i < showDiv.length; i++) {
// var show = document.querySelectorAll('.hide .text'),
// i;
// for (i = 0; i < show.length; i++) {
// show[i].className = 'text shown'; //This adds the ".shown" class to ".text" classes but doesn't show anything because those lists are nested inside other elements that still have the ".hide" class
// }
// }
// console.log(showDiv[i])
// }
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment