I found this nice future to collapse elements on w3schools: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_collapsible_symbol
I would like to revert it, so that all elements are shown when page is loaded, and then use this future to toggle between visible/hidden..
I have this code:
<style>
.collapsible {
background-color: #777;
color: white;
cursor: pointer;
padding: 5px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 12px;
}
.collapsible:after {
content: '\002B';
color: white;
font-weight: bold;
float: right;
margin-left: 5px;
}
.collapsible.active:after {
content: "\2212";
}
.content {
padding: 0 20px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
</style>
<script>
$(document).ready(function() {
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
});
</script>
Example here: https://jsfiddle.net/g50v4cL2/
So when page is loaded, i want to have it like this:
And then able to collapse.. can anyone help me with this?
Thank you.
There're many ways to do it, in this case, I tried to not make many changes and to stick to the way you have, so you can just add active class to your elements, and change your js code a bit to be like this:
var coll = document.getElementsByClassName("collapsible");
var i;
const adjustContentHeight = (content) => {
if (content.style.maxHeight){
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
}
for (i = 0; i < coll.length; i++) {
adjustContentHeight(coll[i].nextElementSibling);
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
adjustContentHeight(this.nextElementSibling);
});
}
.collapsible {
background-color: #777;
color: white;
cursor: pointer;
padding: 5px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 12px;
}
.collapsible:after {
content: '\002B';
color: white;
font-weight: bold;
float: right;
margin-left: 5px;
}
.collapsible.active:after {
content: "\2212";
}
.content {
padding: 0 20px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
<button class='collapsible active'>Test1</button>
<div class='content'>
<label><input type = 'checkbox' value = 'value1'/> value1</label>
<label><input type = 'checkbox' value = 'value2'/> value2</label>
<label><input type = 'checkbox' value = 'value3'/> value3</label>
<label><input type = 'checkbox' value = 'value4'/> value4</label>
</div>
<button class='collapsible active'>Test2</button>
<div class='content'>
<label><input type = 'checkbox' value = 'value5'/> value5</label>
<label><input type = 'checkbox' value = 'value6'/> value6</label>
<label><input type = 'checkbox' value = 'value7'/> value7</label>
</div>
If you don't want to see this transition in the beginning, consider removing the transition property from css and adding it in js after this code
Related
I have created an Accordion with HTML/JS. Everything works fine but when I click a Question, It expands the panel but when I click the same question again It doesn't close.
I have created this script using W3Schools tutorial- https://www.w3schools.com/howto/howto_js_accordion.asp
Here is my code -
var acc = document.getElementsByClassName("accordion1");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
for (j = 0; j < acc.length; j++) {
acc[j].nextElementSibling.style.maxHeight = null;
}
this.classList.toggle("accordion1:active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
.accordion1 {
background-color: #fff;
color: #444;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 14px;
transition: .4s
}
.accordion1:active,
.accordion1:hover {
background-color: #5d4b79;
color: #fff
}
.accordion1:after {
content: '\002B';
color: #fff;
font-weight: 700;
float: right;
margin-left: 5px
}
.accordion1:active:after {
content: "\2212"
}
.panel1 {
padding: 0 18px;
background-color: #fff;
max-height: 0;
overflow: hidden;
transition: max-height .2s ease-out
}
<button class="accordion1">Question 1</button>
<div class="panel1">
<p>Answer 1</p>
</div>
<button class="accordion1">Question 2</button>
<div class="panel1">
<p>Answer 2</p>
</div>
<button class="accordion1">Question 3</button>
<div class="panel1">
<p>Answer 3</p>
</div>
Any help appreciated.
You need to change some code. Jonah Walker Already Resolved this problem.
Here's Codepen Link
He has already commented on his code. Hopefully, your problem will be solved.
var acc = document.getElementsByClassName("accordion");
var i;
// Open the first accordion
var firstAccordion = acc[0];
var firstPanel = firstAccordion.nextElementSibling;
firstAccordion.classList.add("active");
firstPanel.style.maxHeight = firstPanel.scrollHeight + "px";
// Add onclick listener to every accordion element
for (i = 0; i < acc.length; i++) {
acc[i].onclick = function() {
// For toggling purposes detect if the clicked section is already "active"
var isActive = this.classList.contains("active");
// Close all accordions
var allAccordions = document.getElementsByClassName("accordion");
for (j = 0; j < allAccordions.length; j++) {
// Remove active class from section header
allAccordions[j].classList.remove("active");
// Remove the max-height class from the panel to close it
var panel = allAccordions[j].nextElementSibling;
var maxHeightValue = getStyle(panel, "maxHeight");
if (maxHeightValue !== "0px") {
panel.style.maxHeight = null;
}
}
// Toggle the clicked section using a ternary operator
isActive ? this.classList.remove("active") : this.classList.add("active");
// Toggle the panel element
var panel = this.nextElementSibling;
var maxHeightValue = getStyle(panel, "maxHeight");
if (maxHeightValue !== "0px") {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
};
}
// Cross-browser way to get the computed height of a certain element. Credit to #CMS on StackOverflow (http://stackoverflow.com/a/2531934/7926565)
function getStyle(el, styleProp) {
var value, defaultView = (el.ownerDocument || document).defaultView;
// W3C standard way:
if (defaultView && defaultView.getComputedStyle) {
// sanitize property name to css notation
// (hypen separated words eg. font-Size)
styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
} else if (el.currentStyle) { // IE
// sanitize property name to camelCase
styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
return letter.toUpperCase();
});
value = el.currentStyle[styleProp];
// convert other units to pixels on IE
if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
return (function(value) {
var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
el.runtimeStyle.left = el.currentStyle.left;
el.style.left = value || 0;
value = el.style.pixelLeft + "px";
el.style.left = oldLeft;
el.runtimeStyle.left = oldRsLeft;
return value;
})(value);
}
return value;
}
}
button.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
button.accordion.active, button.accordion:hover {
background-color: #ddd;
}
button.accordion:after {
content: '\002B';
color: #777;
font-weight: bold;
float: right;
margin-left: 5px;
}
button.accordion.active:after {
content: "\2212";
}
div.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
<button class="accordion">Question 1</button>
<div class="panel">
<p>Answer 1</p>
</div>
<button class="accordion">Question 2</button>
<div class="panel">
<p>Answer 2</p>
</div>
<button class="accordion">Question 3</button>
<div class="panel">
<p>Answer 3</p>
</div>
I suggest you use a class to set the max-height, since you already have max-height: 0 for class .panel1, you can add another class that sets max-height: none for when the panel is displayed.
var acc = document.getElementsByClassName("accordion1");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
for (j = 0; j < acc.length; j++) {
acc[j].nextElementSibling.classList.remove("panelactive");
}
this.classList.toggle("accordion1:active");
var panel = this.nextElementSibling;
panel.classList.toggle("panelactive");
});
}
.accordion1 {
background-color: #fff;
color: #444;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 14px;
transition: .4s
}
.accordion1:active,
.accordion1:hover {
background-color: #5d4b79;
color: #fff
}
.accordion1:after {
content: '\002B';
color: #fff;
font-weight: 700;
float: right;
margin-left: 5px
}
.accordion1:active:after {
content: "\2212"
}
.panel1 {
padding: 0 18px;
background-color: #fff;
max-height: 0;
overflow: hidden;
transition: max-height .2s ease-out
}
.panelactive {
max-height: none;
}
<button class="accordion1">Question 1</button>
<div class="panel1">
<p>Answer 1</p>
</div>
<button class="accordion1">Question 2</button>
<div class="panel1">
<p>Answer 2</p>
</div>
<button class="accordion1">Question 3</button>
<div class="panel1">
<p>Answer 3</p>
</div>
I've tried a few different ways but can not tell why my.JS isn't opening and closing my accordion. Please check my code. Your help would be appreciated.
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
/*this javascript seems to be fine and matches what some answers have said, and i've reset the page cache but i cannot seem to get it to work */
body {
text-align: center;
background-color: #ffffff;
}
h1 {
font: 40px courier new;
text-align: center;
}
a {
font: 25px arial;
text-align:center;
}
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 60%;
text-align: center;
border: none;
outline: none;
transition: 0.4s;
}
.active, .accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
background-color: white;
overflow: hidden;
font: 16px Source Sans Pro;
width:60%;
margin:0 auto;
display:none;
height:200px auto
}
p{
text-align:center;
}
<div class="wrap1">
<button class="accordion">About Us Page Map</button>
<div id="pan1" class="panel">
<p>
Personel section<br />
Acheivments<br />
History<br />
</p>
</div>
</div>
I've added the css, i do have a class called accordion but it didn't show in the original question sorry!
The problem is here:
var acc = document.getElementsByClassName("accordion");
You don't have "accordion" class in your HTML file, that's why it is not able to recognize it. You have to take a button, assign it a class named accordion and then it will work properly.
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.active,
.accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
}
<button class="accordion">Personal</button>
<div class="panel">
<p>Personal here</p>
</div>
<button class="accordion">Achievements</button>
<div class="panel">
<p>Achievements here</p>
</div>
<button class="accordion">History</button>
<div class="panel">
<p>History here</p>
</div>
Source: HTML and CSS Accordion - w3schools
Hope this helps.
I would suggest refactoring some of your code to make it more readable such as
HTML
Item 1
<div id="item1" class="accordion-content">This is my accordion Item 1 content</div>
Item 2
<div id="item2" class="accordion-content">This is my accordion Item 2 content</div>
JS
document.querySelectorAll(".accordion").forEach(function(node) {
node.addEventListener("click", function(e) {
this.nextElementSibling.toggleClass("active');
});
});
CSS
.accordion-content:not(.active) {
display: none;
}
Besides the refactor, I'm unable to see an element with the className accordion. It seems you are missing the HTML containing the actual accordion.
So I have this page:
I have a list that is made from items in array. If user adds new food the input should go to the array and show new item in the list and the input field should dissapear. Right now I am getting 404 error.
How can I do this?
// find elements
var banner = $("#banner-message")
var button = $("button")
var select = document.getElementById("selectFood");
var options = ["Pizza", "Hambruger", "Salad"];
for (var i = 0; i < options.length; i++) {
var opt = options[i];
var el = document.createElement("option");
el.textContent = opt;
el.value = opt;
select.appendChild(el);
}
function foodInput() {
boxvalue = document.getElementById('addedFood').value;
options.push(boxvalue);
}
function addFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "block") {
x.style.display = "none";
} else {
x.style.display = "block";
}
}
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#banner-message {
background: #778899;
border-radius: 4px;
padding: 20px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
}
button {
background: #A52A2A;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
.addButton {
background: #A52A2A;
color: white;
}
#banner-message.alt {
background: #0084ff;
color: #fff;
margin-top: 40px;
width: 200px;
}
#banner-message.alt button {
background: #fff;
color: #000;
}
.hide {
display: none;
}
.show {
display: block;
}
.demo {
background: #A52A2A;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
#myDIV {
background: #778899;
padding: 20px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
display: none;
}
input[type=submit] {
background: #A52A2A;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="banner-message">
<p>My favorite food</p>
<select id="selectFood">
<option>Select food</option>
</select>
<button>Choose</button>
<br>
<button id="addButton" onclick="addFunction();">
Add new food
</button>
</div>
<div id="myDIV">
<form onsubmit="return foodInput()">
<input type="text" id="addedFood" placeholder="Type food">
<input type="submit" value="Submit" onclick="addFunction()">
</form>
</div>
Actually, I think the problem was with the form trying to reload the fiddle Html page on submit.
Here is the working link of the modified content with some little optimization.
[https://jsfiddle.net/8rvax5z0/3/]
You can add a new method to refresh options after input like:
function refreshFoodInput(options) {
select.removeChild("option");
for (var i = 0; i < options.length; i++) {
var opt = options[i];
var el = document.createElement("option");
el.textContent = opt;
el.value = opt;
select.appendChild(el);
}
}
Then call this method in foodInput method like
function foodInput() {
var boxvalue = document.getElementById('addedFood').value;
options.push(boxvalue);
refreshFoodInput(options);
}
Now your whole code will be like:
// find elements
var banner = $("#banner-message")
var button = $("button")
var select = document.getElementById("selectFood");
var options = ["Pizza", "Hambruger", "Salad"];
refreshFoodInput(options);
function refreshFoodInput(options) {
select.removeChild("option");
for (var i = 0; i < options.length; i++) {
var opt = options[i];
var el = document.createElement("option");
el.textContent = opt;
el.value = opt;
select.appendChild(el);
}
}
function foodInput() {
var boxvalue = document.getElementById('addedFood').value;
options.push(boxvalue);
refreshFoodInput(options);
}
function addFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "block") {
x.style.display = "none";
} else {
x.style.display = "block";
}
}
Hope you get it worked.
Enjoy!
var options = ["Pizza", "Hambruger", "Salad"];
document.querySelector("form#addFoodForm").onsubmit=function(){
let existingFoods=document.querySelector("#selectFood");
const newFood=this.querySelector("input#addedFood").value;
const newFoodOption=document.createElement("option");
newFoodOption.setAttribute("value", newFood);
newFoodOption.innerHTML=newFood;
existingFoods.append(newFoodOption);
refreshFoodOptions(); // This function will add the new foods into the global 'options' array !
return false;
}
function refreshFoodOptions(){
const selectInpt=document.querySelector("#selectFood");
selectInpt.querySelectorAll("option[value]").forEach(function(food){
if(!in_array(food.value, options)) options.push(food.value);
});
console.log( options );
return options;
}
function in_array(key, array){
let exists=false;
array.forEach(function(arrayKey){
if(arrayKey==key) exists=true;
});
return exists;
}
<div id="banner-message">
<p>My favorite food</p>
<select id="selectFood">
<option>Select food</option>
</select>
<button>Choose</button>
</div>
<div id="myDIV">
<form id="addFoodForm">
<input type="text" id="addedFood" placeholder="Type food">
<input type="submit" value="Submit">
</form>
</div>
I could completely redo your code to modernize and reduce it but this is not the idea of the question then I just fixed with this:
Call the options generator (for) when you finishing the push on array because you need to display the new array (select options).
To do it you need to create a function that executes the for and call on first load and every time when new food was added.
Empty the select before add options to prevent duplicated options.
Se the code below:
// find elements
var banner = $("#banner-message")
var button = $("button")
var select = document.getElementById("selectFood");
var options = ["Select Food", "Pizza", "Hambruger", "Salad"];
function generateSeletc(foodArray) {
$('#selectFood').empty();
for (var i = 0; i < options.length; i++) {
var opt = options[i];
var el = document.createElement("option");
el.textContent = opt;
el.value = opt;
select.appendChild(el);
}
}
function foodInput(event) {
event.preventDefault();
boxvalue = document.getElementById('addedFood').value;
options.push(boxvalue);
generateSeletc(options);
}
function addFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "block") {
x.style.display = "none";
} else {
x.style.display = "block";
}
}
generateSeletc(options);
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#banner-message {
background: #778899;
border-radius: 4px;
padding: 20px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
}
button {
background: #A52A2A;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
.addButton {
background: #A52A2A;
color: white;
}
#banner-message.alt {
background: #0084ff;
color: #fff;
margin-top: 40px;
width: 200px;
}
#banner-message.alt button {
background: #fff;
color: #000;
}
.hide {
display: none;
}
.show {
display: block;
}
.demo {
background: #A52A2A;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
#myDIV {
background: #778899;
padding: 20px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
display: none;
}
input[type=submit] {
background: #A52A2A;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="banner-message">
<p>My favorite food</p>
<select id="selectFood">
<option>Select food</option>
</select>
<button>Choose</button>
<br>
<button id="addButton" onclick="addFunction();">
Add new food
</button>
</div>
<div id="myDIV">
<form onsubmit="return foodInput(event)">
<input type="text" id="addedFood" placeholder="Type food">
<input type="submit" value="Submit" onclick="addFunction()">
</form>
</div>
TLDR; The functionality I'm trying to create in this code example is upon clicking a box (collapsible has active class), and then you click on the search box, the active class is removed closing the collapsible. Currently, the remove class is not working. Any idea why?
In more detail:
I have a list of collapsible blocks get an active class when they are clicked. You can search a search box to filter out which block you want to be displayed, and thus click on it to display more content. I have realized that when you go back to search and didn't 'unclick' a box (to close the collapsible) the box is still active (which makes perfect sense).
I had an idea that upon search box focus, I would loop through all the collapsible and remove the active class itself (in turn, closing the collapsible).
I've gotten to the point where I can find which collapsible is active, but I cannot remove the active class.
Is this because the box was initially clicked to add the class and has to be physically clicked once again to remove it?
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
function searchClick() {
var searchTable;
searchTable = document.getElementById("search-table");
faqButtons = searchTable.getElementsByTagName("button");
for (i = 0; i < faqButtons.length; i++) {
if (faqButtons[i].classList.contains("active")) {
console.log('THIS ONE: ', faqButtons[i]);
faqButtons[i].classList.remove("active");
}
}
}
.collapsible {
display: flex;
justify-content: space-between;
background-color: white;
color: black;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 20px;
}
.collapsible span {
padding-left: 5px;
padding-right: 5px;
}
.collapsible .active,
.collapsible:hover {
background-color: #333;
color: white;
}
.content {
padding: 0 18px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
.content p {
margin-top: 10px;
}
<div class="search-faq">
<input autocomplete="off" type="text" id="search-faq" placeholder="Search for FAQ" onfocus="searchClick()" />
</div>
<div id="search-table" class="superHidden">
<div id="wolfandgrizzly-FAQ-search">
<h1>A to B sales</h1>
<button class="collapsible"><span>What are our shipping policies?</span></button>
<div class="content">
<p>
They are crazy cool.
</p>
</div>
<button class="collapsible"><span>Are you making more products?</span></button>
<div class="content">
<p>
We'll sell you more very soon
</p>
</div>
</div>
I don't see where you are getting that the active class is not being removed. It doesn't appear that there is a problem with that. I think the problem is that you are showing the answers via maxHeight setting, but you aren't resetting it when you click the search box. I've updated it in this snippet, but essentially it boiled down to adding the following in your loop:
var content = faqButtons[i].nextElementSibling
content.style.maxHeight = null
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
function searchClick() {
var searchTable;
searchTable = document.getElementById("search-table");
faqButtons = searchTable.getElementsByTagName("button");
for (i = 0; i < faqButtons.length; i++) {
if (faqButtons[i].classList.contains("active")) {
console.log('THIS ONE: ', faqButtons[i]);
faqButtons[i].classList.remove("active");
}
var content = faqButtons[i].nextElementSibling
content.style.maxHeight = null
}
}
.collapsible {
display: flex;
justify-content: space-between;
background-color: white;
color: black;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 20px;
}
.collapsible span {
padding-left: 5px;
padding-right: 5px;
}
.collapsible .active,
.collapsible:hover {
background-color: #333;
color: white;
}
.content {
padding: 0 18px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
.content p {
margin-top: 10px;
}
<div class="search-faq">
<input autocomplete="off" type="text" id="search-faq" placeholder="Search for FAQ" onfocus="searchClick()" />
</div>
<div id="search-table" class="superHidden">
<div id="wolfandgrizzly-FAQ-search">
<h1>A to B sales</h1>
<button class="collapsible"><span>What are our shipping policies?</span></button>
<div class="content">
<p>
They are crazy cool.
</p>
</div>
<button class="collapsible"><span>Are you making more products?</span></button>
<div class="content">
<p>
We'll sell you more very soon
</p>
</div>
</div>
Here's an approach that uses as little JavaScript as possible. If JavaScript is disabled, the only thing that will break is the search box. Sections will still open and close as expected when clicked.
The accordion stores its state in checkboxes, one in each section. Each section's title is a label element which toggles that section's checkbox when clicked. The sections are expanded and collapsed using CSS :checked selectors.
var sections = [].slice.call(document.querySelectorAll(".accordion li")),
searchAccordion = function() {
var value = document.getElementById("search").value.toLowerCase();
sections.map(function(section) {
var content = section.textContent.toLowerCase();
section.querySelector("input").checked = content.includes(value);
});
};
body {
font-family: sans-serif;
}
.accordion {
padding-left: 0;
margin: -1rem;
}
.accordion li {
list-style-type: none;
}
.accordion input {
display: none;
}
.accordion label {
background-color: #eee;
transition: background-color 100ms;
cursor: pointer;
font-size: 1.2rem;
padding: 1rem;
display: block;
}
.accordion label:hover {
background-color: #444;
color: white;
}
.accordion .content {
padding: 1rem;
display: none;
}
.accordion input:checked ~ .content {
display: block;
}
<input id="search" onKeyup="searchAccordion()" type="text" placeholder="Search for FAQ" autocomplete="off">
<h1>A to B sales</h1>
<ul class="accordion">
<li>
<input type="checkbox" id="section1">
<label for="section1">What are our shipping policies?</label>
<div class="content">They are crazy cool.</div>
</li>
<li>
<input type="checkbox" id="section2">
<label for="section2">Are you making more products?</label>
<div class="content">We'll sell you more very soon</div>
</li>
</ul>
What I want: User types word into input bar -> user presses Add button -> word is added to two lists "unsortedUL" and "sortedUL" - > user presses Sort button -> the list "sortedUL" gets sorted by descending (z-a), while "unsortedUL" remains exactly how the user inputted it.
I cannot figure out how to get TWO lists while only ONE of them is sorted.
var myNodelist = document.getElementsByTagName("LI");
var i;
for (i = 0; i < myNodelist.length; i++) {
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
myNodelist[i].appendChild(span);
}
var close = document.getElementsByClassName("close");
var i;
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
function newElement() {
var li = document.createElement("li");
var inputValue = document.getElementById("myInput").value;
var t = document.createTextNode(inputValue);
li.appendChild(t);
if (inputValue === '') {
alert("You must write a word!");
} else {
document.getElementById("sortedUL").appendChild(li);
}
document.getElementById("myInput").value = "";
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
li.appendChild(span);
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
}
function sortList() {
var list, i, switching, b, shouldSwitch;
list = document.getElementById("sortedUL");
switching = true;
while (switching) {
switching = false;
b = list.getElementsByTagName("LI");
for (i = 0; i < (b.length - 1); i++) {
shouldSwitch = false;
if (b[i].innerHTML.toLowerCase() < b[i + 1].innerHTML.toLowerCase()) {
shouldSwitch= true;
break;
}
}
if (shouldSwitch) {
b[i].parentNode.insertBefore(b[i + 1], b[i]);
switching = true;
}
}
}
document.getElementById("date").innerHTML = new Date().toDateString();
document.getElementById("time").innerHTML = new Date().toLocaleTimeString();
body {
margin: 0;
min-width: 250px;
background-color: green;
}
* {
box-sizing: border-box;
}
ul {
margin: 0;
padding: 0;
width: 100%;
float: right;
}
ul li {
cursor: pointer;
position: relative;
padding: 12px 8px 12px 40px;
list-style-type: number;
background: #eee;
font-size: 18px;
transition: 0.2s;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.close {
position: absolute;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.header {
background-color: green;
padding: 30px 40px;
color: white;
text-align: center;
}
.header:after {
content: "";
display: table;
clear: both;
}
input {
border: none;
width: 50%;
padding: 10px;
float: center;
font-size: 16px;
}
.addBtn {
padding: 10px;
width: 10%;
background: #d9d9d9;
color: #555;
float: right;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
}
.sortBtn {
padding: 10px;
width: 10%;
background: #d9d9d9;
color: #555;
float: left;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
}
<!DOCTYPE html>
<html>
<title>Assignment Two</title>
<body>
<h1 style="color:white;"align="center"id="date"></h1>
<h1 style="color:white;"align="center"id="time"></h1>
<div id="myDIV" class="header">
<h2 style="margin:5px">Enter a list of words</h2>
<input type="text" id="myInput" placeholder="Word...">
<span onclick="newElement()" class="addBtn">Add</span>
<span onclick="sortList()" class="sortBtn">Sort</span>
</div>
<ul id="sortedUL">
</ul>
<ul id="unsortedUL">
</ul>
</body>
</html>
You have to clone the HTML Node to append it twice.
Or create it twice like I did.
var myNodelist = document.getElementsByTagName("LI");
var i;
for (i = 0; i < myNodelist.length; i++) {
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
myNodelist[i].appendChild(span);
}
var close = document.getElementsByClassName("close");
var i;
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
function newElement() {
if (inputValue === '') {
alert("You must write a word!");
} else {
var li = document.createElement("li");
var inputValue = document.getElementById("myInput").value;
var t = document.createTextNode(inputValue);
li.appendChild(t);
document.getElementById("sortedUL").appendChild(li);
var li = document.createElement("li");
var inputValue = document.getElementById("myInput").value;
var t = document.createTextNode(inputValue);
li.appendChild(t);
document.getElementById("unsortedUL").appendChild(li);
}
document.getElementById("myInput").value = "";
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
li.appendChild(span);
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
}
function sortList() {
var list, i, switching, b, shouldSwitch;
list = document.getElementById("sortedUL");
switching = true;
while (switching) {
switching = false;
b = list.getElementsByTagName("LI");
for (i = 0; i < (b.length - 1); i++) {
shouldSwitch = false;
if (b[i].innerHTML.toLowerCase() < b[i + 1].innerHTML.toLowerCase()) {
shouldSwitch= true;
break;
}
}
if (shouldSwitch) {
b[i].parentNode.insertBefore(b[i + 1], b[i]);
switching = true;
}
}
}
document.getElementById("date").innerHTML = new Date().toDateString();
document.getElementById("time").innerHTML = new Date().toLocaleTimeString();
body {
margin: 0;
min-width: 250px;
background-color: green;
}
* {
box-sizing: border-box;
}
p {
font-size: 16px;
margin-left: 20px;
color: white;
text-transform: uppercase;
}
ul {
margin: 0 0 20px 0;
padding: 0;
width: 100%;
float: right;
}
ul li {
cursor: pointer;
position: relative;
padding: 12px 8px 12px 40px;
list-style-type: number;
background: #eee;
font-size: 18px;
transition: 0.2s;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.close {
position: absolute;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.header {
background-color: green;
padding: 30px 40px;
color: white;
text-align: center;
}
.header:after {
content: "";
display: table;
clear: both;
}
input {
border: none;
width: 50%;
padding: 10px;
float: center;
font-size: 16px;
}
.addBtn {
padding: 10px;
width: 10%;
background: #d9d9d9;
color: #555;
float: right;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
}
.sortBtn {
padding: 10px;
width: 10%;
background: #d9d9d9;
color: #555;
float: left;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
}
<!DOCTYPE html>
<html>
<title>Assignment Two</title>
<body>
<h1 style="color:white;"align="center"id="date"></h1>
<h1 style="color:white;"align="center"id="time"></h1>
<div id="myDIV" class="header">
<h2 style="margin:5px">Enter a list of words</h2>
<input type="text" id="myInput" placeholder="Word...">
<span onclick="newElement()" class="addBtn">Add</span>
<span onclick="sortList()" class="sortBtn">Sort</span>
</div>
<p>Sorted</p>
<ul id="sortedUL">
</ul>
<p>Unsorted</p>
<ul id="unsortedUL">
</ul>
</body>
</html>
While you need list you can use Javascript Array
Here you can have two Arrays which would be SortedList and UnsortedList
I have declare both the list globally so that you can sort one list and keep one list without change
Refer The Below Code for the Work Flow
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form>
<div>
<input type="text" name="txtName" id="txtName"/>
<input type="button" value="Add" onclick="AddToList()"/>
<input type="button" value="Sort" onclick="SortList()"/>
</div>
</form>
</body>
</html>
<script>
var sortedList = [];
var unsortedList = [];
function AddToList() {
var data = document.getElementById("txtName").value;
sortedList.push(data);
unsortedList.push(data);
}
function SortList() {
sortedList.sort();
sortedList.reverse();
console.log(sortedList);
console.log(unsortedList);
}
</script>
Here I have created two buttons as you said
And Called a function to sort and other to add in the List.
As you said you need the Unsorted List to be as it is, So in the SortList() function we have printed sortedList and unsortedList Both two see a diffrence.
As expected sortedList will print the descending order data and unsortedList will print normal data.
You just need to insert it into both lists as each word is added, i.e. where you have:
document.getElementById("sortedUL").appendChild(li);
you should add a second line like this:
document.getElementById("unsortedUL").appendChild(li.cloneNode(true));
The node cloning might be what you were missing if you tried it before, otherwise it would move the same element and it ends up in only one list. The 'true' argument makes a deep copy so that the text node underneath it is copied as well.
Incidentally, this whole operation would be a lot easier with jQuery, it's the kind of DOM manipulation that the library was meant for. However people jump to jQuery so quickly and it's good that you are doing it with vanilla JavaScript.