Javascript Improve collapsing element - javascript

I have created this toggle script which works well but I need to improve it so that onclick, any previously collapsed (i.e. open) subcats would simultaneously close and only the one clicked should collapse (i.e. open).
var collapse = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < collapse.length; i++) {
collapse[i].addEventListener("click", function() {
this.classList.toggle("activeCollapse");
var content = this.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
.catColumn {
width: 400px;
margin: 0 auto;
}
.collapsible {
width: 100%;
padding: 14px 8px;
margin-top: 10px;
color: #5a2e0f;
background-color: #fff;
border: 1px solid #c1bfbf;
outline: none;
border-radius: 6px;
}
.collapsible:hover {
background-color: #efdac6;
}
.collapsible:after {
float: right;
content: '\002B';
color: #5a2e0f;
font-size: 1.8em;
margin-left: 5px;
cursor: pointer;
line-height: 26px;
}
.activeCollapse {
background-color: #efdac6;
border-radius: 0;
border-bottom: 0px;
}
.activeCollapse:after {
content: "\2212";
}
/**/
ul.subcats {
width: 100%;
max-height: 0;
transition: max-height 1s ease-out;
overflow: hidden;
font-size: 13px;
}
ul.subcats li {
padding: 12px;
}
<div class="catColumn">
<div class="collapsible">cat1</div>
<ul class="subcats">
<li>subcat1</li>
<li>subcat2</li>
</ul>
<div class="collapsible">cat2</div>
<ul class="subcats">
<li>subcat3</li>
<li>subcat4</li>
</ul>
</div>

var collapse = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < collapse.length; i++) {
collapse[i].addEventListener("click", function() {
this.classList.toggle("activeCollapse");
for (j = 0; j < collapse.length; j++) {
this.classList.remove("activeCollapse");
if(j!=i)
collapse[j].nextElementSibling.style.maxHeight = null;
var content = this.nextElementSibling;
}
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
.catColumn {
width: 400px;
margin: 0 auto;
}
.collapsible {
width: 100%;
padding: 14px 8px;
margin-top: 10px;
color: #5a2e0f;
background-color: #fff;
border: 1px solid #c1bfbf;
outline: none;
border-radius: 6px;
}
.collapsible:hover {
background-color: #efdac6;
}
.collapsible:after {
float: right;
content: '\002B';
color: #5a2e0f;
font-size: 1.8em;
margin-left: 5px;
cursor: pointer;
line-height: 26px;
}
.activeCollapse {
background-color: #efdac6;
border-radius: 0;
border-bottom: 0px;
}
.activeCollapse:after {
content: "\2212";
}
/**/
ul.subcats {
width: 100%;
max-height: 0;
transition: max-height 1s ease-out;
overflow: hidden;
font-size: 13px;
}
ul.subcats li {
padding: 12px;
}
<div class="catColumn">
<div class="collapsible">cat1</div>
<ul class="subcats">
<li>subcat1</li>
<li>subcat2</li>
</ul>
<div class="collapsible">cat2</div>
<ul class="subcats">
<li>subcat3</li>
<li>subcat4</li>
</ul>
</div>

First, loop through the open elements and remove the class and set max height to null. Then do your normal code.
I also changed your event Listener so you only have one instead of one for each element.
var collapse = document.querySelector(".catColumn");
collapse.addEventListener("click", function(e) {
let el = e.target;
let hideSelf = (el.className.indexOf("activeCollapse") > 0);
if (el.className.indexOf("collapsible") > -1) {
let shown = document.querySelectorAll(".activeCollapse");
shown.forEach(function(activeEl) {
activeEl.classList.remove("activeCollapse");
activeEl.nextElementSibling.style.maxHeight = null;
});
if (hideSelf == false) {
el.classList.toggle("activeCollapse");
var content = el.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
}
}
});
.catColumn {
width: 400px;
margin: 0 auto;
}
.collapsible {
width: 100%;
padding: 14px 8px;
margin-top: 10px;
color: #5a2e0f;
background-color: #fff;
border: 1px solid #c1bfbf;
outline: none;
border-radius: 6px;
}
.collapsible:hover {
background-color: #efdac6;
}
.collapsible:after {
float: right;
content: '\002B';
color: #5a2e0f;
font-size: 1.8em;
margin-left: 5px;
cursor: pointer;
line-height: 26px;
}
.activeCollapse {
background-color: #efdac6;
border-radius: 0;
border-bottom: 0px;
}
.activeCollapse:after {
content: "\2212";
}
/**/
ul.subcats {
width: 100%;
max-height: 0;
transition: max-height 1s ease-out;
overflow: hidden;
font-size: 13px;
}
ul.subcats li {
padding: 12px;
}
<div class="catColumn">
<div class="collapsible">cat1</div>
<ul class="subcats">
<li>subcat1</li>
<li>subcat2</li>
</ul>
<div class="collapsible">cat2</div>
<ul class="subcats">
<li>subcat3</li>
<li>subcat4</li>
</ul>
</div>

var parentDiv = document.getElementsByClassName("catColumn")[0];
parentDiv.addEventListener("click",function(e){
let current= e.target;
var collapse = document.getElementsByClassName("collapsible");
let toExpand = !current.nextElementSibling.style.maxHeight ;
for (let i = 0; i < collapse.length; i++) {
var content = collapse[i].nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
collapse[i].classList.toggle("activeCollapse");
}
}
let toToggle = current.nextElementSibling;
if(toExpand ){
toToggle.style.maxHeight = content.scrollHeight + "px";
current.classList.toggle("activeCollapse");
}
});
.catColumn {
width: 400px;
margin: 0 auto;
}
.collapsible {
width: 100%;
padding: 14px 8px;
margin-top: 10px;
color: #5a2e0f;
background-color: #fff;
border: 1px solid #c1bfbf;
outline: none;
border-radius: 6px;
}
.collapsible:hover {
background-color: #efdac6;
}
.collapsible:after {
float: right;
content: '\002B';
color: #5a2e0f;
font-size: 1.8em;
margin-left: 5px;
cursor: pointer;
line-height: 26px;
}
.activeCollapse {
background-color: #efdac6;
border-radius: 0;
border-bottom: 0px;
}
.activeCollapse:after {
content: "\2212";
}
/**/
ul.subcats {
width: 100%;
max-height: 0;
transition: max-height 1s ease-out;
overflow: hidden;
font-size: 13px;
}
ul.subcats li {
padding: 12px;
}
<div class="catColumn">
<div class="collapsible">cat1</div>
<ul class="subcats">
<li>subcat1</li>
<li>subcat2</li>
</ul>
<div class="collapsible">cat2</div>
<ul class="subcats">
<li>subcat3</li>
<li>subcat4</li>
</ul>
</div>

Related

Why won't these for loops work? To-Do list app [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Event binding on dynamically created elements?
(23 answers)
Closed last year.
I can't figure out why the for loops won't iterate. I had them working at one point inside of the printInput function, but not outside. BTW, I'm still working on the code portion of the for both loops. One is supposed to close the object by removing it. The other is supposed to make the html element editable.
// close button
var closes = document.getElementsByClassName("closes");
for (var i = 0; i < closes.length; i++){
closes[i].onclick = function (){
var l = closes[i];
l.remove();
}
}
// edit button
var edit = document.getElementsByClassName("edit");
for(var i = 0; i < edit.length; i++){
edit[i].onclick = function (){
var x = this.parentElement;
x.contentEditable = true;
}
}
// Submits input by hitting enter
document.addEventListener("keyup", function(e) {
if (e.keyCode === 13) {
printInput();
}
});
// Toggles checked class for finished chores
let selection = document.querySelector('ul');
selection.addEventListener("click", function(event) {
if (event.target.tagName === 'LI') {
event.target.classList.toggle('checked');
}
}, false);
// This creates a new list object.
function printInput() {
let input = document.getElementById('todotext').value;
if (input === "" || null){
alert("You haven't written anything!");
} else {
const newItem = document.createElement('li');
const newNode = document.createTextNode(input);
newItem.className = "closes";
newItem.appendChild(newNode);
document.getElementById("list").appendChild(newItem);
const img = document.createElement("img");
img.src = 'edit.png';
img.className = "edit";
const newSpan = document.createElement("span");
const xBtn = document.createTextNode("x");
newSpan.className = "close";
newSpan.appendChild(xBtn);
newItem.appendChild(img);
newItem.appendChild(newSpan);
document.getElementById("todotext").value = "";
}
}
body {
min-width: 850px;
font-family: sans-serif;
background-color: #ece0d9;
}
h1.title {
width: auto;
margin: auto;
padding: 25px;
text-align: center;
-webkit-text-stroke: 1px #460a1e; /* width and color */
font-family: sans-serif; color: white;
}
div.form {
display: flex;
padding: 10px;
width: 50%;
margin: auto;
}
input {
width: 75%;
padding: 10px 14px 11px 14px;
margin: 0;
border-radius: 0;
border-width: thin;
font-size: inherit;
}
input:focus {
border-radius: 0;
outline: none;
}
span.addTo {
width: 25%;
padding: 8px 14px 10px 14px;
margin: 0;
border-style: solid;
border-width: thin;
border-color: black;
border-left: none;
text-align: center;
background-color: rgb(236, 235, 235);
}
span.addTo:hover {
background-color: #e0e0e0;
cursor: pointer;
}
ul.list{
width: 50%;
display: table;
text-align: left;
padding: 0;
margin: auto;
}
ul.list li{
padding: 10px 10px;
background-color: snow;
clear: right;
margin: 0;
position: relative;
cursor: pointer;
}
ul.list li:nth-child(2n){
background-color: rgb(240, 239, 239);
}
ul.list li.checked:nth-child(2n){
text-decoration: line-through;
background-color: rgb(170, 168, 168);
}
ul li.checked {
text-decoration: line-through;
background-color: rgb(170, 168, 168);
}
img.edit {
position: absolute;
right: 40px;
top: 0;
padding: 1px;
width: 34px;
height: 36.4px;
cursor: pointer;
background-color: transparent;
color: rgb(75, 71, 71);
}
img.edit:hover {
padding: 0;
width: 34px;
height: 36.4px;
transition-property: background-color;
transition-duration: .3s;
border-style: ridge;
border-color: black;
border-width: 1px;
}
span.close {
position: absolute;
right: 0;
top: 0;
padding: 10px 14px 10px 14px;
cursor: pointer;
background-color: transparent;
color: rgb(75, 71, 71);
}
span.close:hover {
color: black;
padding: 9px 13px 9px 13px;
transition-property: background-color;
transition-duration: .3s;
border-style: ridge;
border-color: black;
border-width: 1px;
}
<!DOCTYPE html>
<html>
<head>
<title>To-Do List</title>
<meta charset="en">
<link rel="stylesheet" href="main.css">
</head>
<body>
<h1 class="title">To-Do List</h1>
<div class="form">
<input type="text" id="todotext">
<span onclick="printInput()" id="addTo" class="addTo">Add</span>
</div>
<ul style="list-style-type:none;" class="list" id="list">
<li hidden id="close">Clean room<img src="edit.png" class="edit"><span class="close">x</span></li>
</ul>
<script src="main.js">
</script>
</body>
</html>

Javascript removeChild doesn't work as expected

I have a code that gets characters names and gender after clicking on film name. This information appears in modal window and my goal is to delete HTML element with characters every time I close modal, so if I select another film the new set of characters will appear, and the old one is already deleted.
The problem is that removeChild method doesn't work as expected. I've tried different variations including parentNode but nothing helped.
Here is the code:
window.addEventListener('DOMContentLoaded', function() {
let btn = document.querySelector('.sw-btn');
let content = document.querySelector('.content');
let modal = document.querySelector('.modal');
let modalBody = document.querySelector('.modal-body');
let closeBtn = document.querySelector('.close-btn');
let filmsList = document.createElement('ul');
let charsList = document.createElement('ol');
function getFilms() {
axios.get('https://swapi.co/api/films/').then(res => {
content.appendChild(filmsList);
for (var i = 0; i < res.data.results.length; i++) {
res.data.results.sort(function(a, b) {
let dateA = new Date(a.release_date),
dateB = new Date(b.release_date);
return dateA - dateB;
});
(function updateFilms() {
let addFilm = document.createElement('li');
filmsList.appendChild(addFilm);
let addFilmAnchor = document.createElement('a');
let addFilmId = document.createElement('p');
let addFilmCrawl = document.createElement('p');
let addFilmDirector = document.createElement('p');
let addFilmDate = document.createElement('p');
addFilmAnchor.textContent = res.data.results[i].title;
addFilmId.textContent = `Episode ID: ${res.data.results[i].episode_id}`;
addFilmCrawl.textContent = `Episode description: ${res.data.results[i].opening_crawl}`;
addFilmDirector.textContent = `Episode director: ${res.data.results[i].director}`;
addFilmDate.textContent = `Episode release date: ${res.data.results[i].release_date}`;
addFilm.append(addFilmAnchor, addFilmId, addFilmCrawl, addFilmDirector, addFilmDate);
})();
}
let links = document.getElementsByTagName('a');
for (let j = 0; j < links.length; j++) {
links[j].onclick = function() {
modal.style.display = 'block';
modalBody.appendChild(charsList);
let chars = res.data.results[j].characters;
for (let k = 0; k < chars.length; k++) {
const element = chars[k];
axios.get(element).then(res => {
let addChar = document.createElement('li');
charsList.appendChild(addChar);
let addCharName = document.createElement('p');
let addCharGender = document.createElement('p');
addCharName.textContent = `Character name: ${res.data.name}`;
addCharGender.textContent = `Character gender: ${res.data.gender}`;
addChar.append(addCharName, addCharGender);
})
}
closeBtn.addEventListener('click', () => {
modal.style.display = 'none';
console.log(modalBody.childNodes[0]);
// Problem is here
modalBody.removeChild(modalBody.childNodes[0]);
});
window.addEventListener('click', (e) => {
if (e.target == modal) {
modal.style.display = 'none';
console.log(modalBody.childNodes[0]);
modalBody.removeChild(modalBody.childNodes[0]);
}
})
}
}
}).catch(err => {
console.log("An error occured");
})
};
btn.addEventListener('click', getFilms);
closeBtn.addEventListener('click', () => {
modal.style.display = 'none';
});
window.addEventListener('click', (e) => {
if (e.target == modal) {
modal.style.display = 'none';
}
})
});
body {
max-height: 100vh;
padding: 0;
margin: 0;
font-family: Muli;
}
body::before {
background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Star_Wars_Logo.svg/1200px-Star_Wars_Logo.svg.png') no-repeat center / cover;
background-size: cover;
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -2;
opacity: 0.1;
}
h1 {
text-align: center;
color: #660d41;
font-size: 3em;
margin-top: 10px;
letter-spacing: 1px;
}
main {
display: flex;
align-items: center;
flex-direction: column;
}
.content {
max-width: 55%;
overflow-y: scroll;
max-height: 75vh;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
background-color: #f4f4f4;
margin: 20% auto;
width: 40%;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.2);
animation: modalOpen 1s;
}
.modal-header {
background: coral;
padding: 15px;
color: white;
letter-spacing: 1px;
position: relative;
}
.modal-header h2 {
margin: 0;
}
.modal-body {
padding: 10px 20px;
}
.close-btn {
color: white;
float: right;
font-size: 30px;
position: absolute;
top: 0px;
right: 10px;
}
.close-btn:hover,
.close-btn:focus {
color: black;
text-decoration: none;
cursor: pointer;
transition: all 0.4s ease-in;
}
ul {
list-style-type: none;
padding: 10px 20px;
}
li {
border-bottom: 1px solid orangered;
margin-bottom: 30px;
}
li:last-child {
border-bottom: none;
margin-bottom: 0;
}
a {
font-size: 1.7em;
color: #b907d9;
cursor: pointer;
margin-bottom: 10px;
}
p {
font-size: 1.2rem;
color: #0f063f;
margin: 10px 0;
}
button {
padding: .5em 1.5em;
border: none;
color: white;
transition: all 0.2s ease-in;
background: #da2417;
border-radius: 20px;
font-size: 1em;
cursor: pointer;
margin-top: 15px;
}
button:focus {
outline: none;
}
button:hover {
background: #e7736b;
}
button:active {
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.7) inset;
}
#keyframes modalOpen {
from {
opacity: 0
}
to {
opacity: 1
}
}
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<h1>Star wars films</h1>
<main>
<div class="content"></div>
<div class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close-btn">×</span>
<h2>Episode Characters</h2>
</div>
<div class="modal-body"></div>
</div>
</div>
<button class="sw-btn">Find Films</button>
</main>
Any help would be appreciated.
The problem is that you are using the same ol element when appending the characters to the list, since you instantiate it at the beginning and re-use it later: let charsList = document.createElement('ol');
When you close the modal, you will remove that ol element from the modal, but you will not remove its content. When opening the modal again, the ol will be added again - with your old content.
If you move the declaration of charsList inside your onclick handler, it will work.
Also, you should register the close handlers of your modal only once. Otherwise, it will be called as often as you open your modal.
Demo:
window.addEventListener('DOMContentLoaded', function () {
let btn = document.querySelector('.sw-btn');
let content = document.querySelector('.content');
let modal = document.querySelector('.modal');
let modalBody = document.querySelector('.modal-body');
let closeBtn = document.querySelector('.close-btn');
let filmsList = document.createElement('ul');
closeBtn.addEventListener('click', () => {
modal.style.display = 'none';
console.log(modalBody.childNodes[0]);
modalBody.removeChild(modalBody.childNodes[0]);
});
window.addEventListener('click', (e) => {
if (e.target == modal) {
modal.style.display = 'none';
console.log(modalBody.childNodes[0]);
modalBody.removeChild(modalBody.childNodes[0]);
}
})
function getFilms() {
axios.get('https://swapi.co/api/films/').then(res => {
content.appendChild(filmsList);
for (var i = 0; i < res.data.results.length; i++) {
res.data.results.sort(function (a, b) {
let dateA = new Date(a.release_date),
dateB = new Date(b.release_date);
return dateA - dateB;
});
(function updateFilms() {
let addFilm = document.createElement('li');
filmsList.appendChild(addFilm);
let addFilmAnchor = document.createElement('a');
let addFilmId = document.createElement('p');
let addFilmCrawl = document.createElement('p');
let addFilmDirector = document.createElement('p');
let addFilmDate = document.createElement('p');
addFilmAnchor.textContent = res.data.results[i].title;
addFilmId.textContent = `Episode ID: ${res.data.results[i].episode_id}`;
addFilmCrawl.textContent = `Episode description: ${res.data.results[i].opening_crawl}`;
addFilmDirector.textContent = `Episode director: ${res.data.results[i].director}`;
addFilmDate.textContent = `Episode release date: ${res.data.results[i].release_date}`;
addFilm.append(addFilmAnchor, addFilmId, addFilmCrawl, addFilmDirector, addFilmDate);
})();
}
let links = document.getElementsByTagName('a');
for (let j = 0; j < links.length; j++) {
links[j].onclick = function () {
modal.style.display = 'block';
let charsList = document.createElement('ol');
modalBody.appendChild(charsList);
let chars = res.data.results[j].characters;
for (let k = 0; k < chars.length; k++) {
const element = chars[k];
axios.get(element).then(res => {
let addChar = document.createElement('li');
charsList.appendChild(addChar);
let addCharName = document.createElement('p');
let addCharGender = document.createElement('p');
addCharName.textContent = `Character name: ${res.data.name}`;
addCharGender.textContent = `Character gender: ${res.data.gender}`;
addChar.append(addCharName, addCharGender);
})
}
}
}
}).catch(err => {
console.log("An error occured");
})
};
btn.addEventListener('click', getFilms);
closeBtn.addEventListener('click', () => {
modal.style.display = 'none';
});
window.addEventListener('click', (e) => {
if (e.target == modal) {
modal.style.display = 'none';
}
})
});
body {
max-height: 100vh;
padding: 0;
margin: 0;
font-family: Muli;
}
body::before {
background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Star_Wars_Logo.svg/1200px-Star_Wars_Logo.svg.png') no-repeat center / cover;
background-size: cover;
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -2;
opacity: 0.1;
}
h1 {
text-align: center;
color: #660d41;
font-size: 3em;
margin-top: 10px;
letter-spacing: 1px;
}
main {
display: flex;
align-items: center;
flex-direction: column;
}
.content {
max-width: 55%;
overflow-y: scroll;
max-height: 75vh;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
background-color: #f4f4f4;
margin: 20% auto;
width: 40%;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.2);
animation: modalOpen 1s;
}
.modal-header {
background: coral;
padding: 15px;
color: white;
letter-spacing: 1px;
position: relative;
}
.modal-header h2 {
margin: 0;
}
.modal-body {
padding: 10px 20px;
}
.close-btn {
color: white;
float: right;
font-size: 30px;
position: absolute;
top: 0px;
right: 10px;
}
.close-btn:hover,
.close-btn:focus {
color: black;
text-decoration: none;
cursor: pointer;
transition: all 0.4s ease-in;
}
ul {
list-style-type: none;
padding: 10px 20px;
}
li {
border-bottom: 1px solid orangered;
margin-bottom: 30px;
}
li:last-child {
border-bottom: none;
margin-bottom: 0;
}
a {
font-size: 1.7em;
color: #b907d9;
cursor: pointer;
margin-bottom: 10px;
}
p {
font-size: 1.2rem;
color: #0f063f;
margin: 10px 0;
}
button {
padding: .5em 1.5em;
border: none;
color: white;
transition: all 0.2s ease-in;
background: #da2417;
border-radius: 20px;
font-size: 1em;
cursor: pointer;
margin-top: 15px;
}
button:focus {
outline: none;
}
button:hover {
background: #e7736b;
}
button:active {
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.7) inset;
}
#keyframes modalOpen {
from {
opacity: 0
}
to {
opacity: 1
}
}
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<h1>Star wars films</h1>
<main>
<div class="content"></div>
<div class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close-btn">×</span>
<h2>Episode Characters</h2>
</div>
<div class="modal-body"></div>
</div>
</div>
<button class="sw-btn">Find Films</button>
</main>
Do this charsList.innerText = ''; when click close button.
When you call removeChild you take off the <ol> from modalbody in UI. You can see the modalBody is empty after clicking close button.
But you already store the <ol> element in js variable by let charsList = document.createElement('ol'); so the ol element itself doesn't change actually.
The <li> element still inside the <ol>. Then you add more new <li> and put it back to modalBody.
My solution is remove all element in <ol> when clicking close button.

Javascript let user choose element

https://gyazo.com/aa49eb6d6849b3adabb8924aa9e40594
I have the elements in the diagram and I want to let the user choose in which element they are going to add the semi column to add text, but I dont know how to let them select a element and then add according to that selection.
var addDetail = document.getElementById('addDetail');
var clauseInput = document.getElementsByClassName('clause');
document.addEventListener('click', function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
if(target == clauseInput[0] || target == clauseInput[1] ||
target == clauseInput[2] || target == clauseInput[3] ||
target == clauseInput[4] || target == addDetail) {
document.getElementById('addDetail').style.display='inline-block';
// createDetail();
console.log(target);
} else {
document.getElementById('addDetail').style.display='none';
}
}, false);
Update
Instead of searching through all clause elements every time when addDetail been clicked, there is e.relatedTarget that really suitable to your problem, detailed documentation, and the update snippet :
/*CREATE TOP AND BOTTOM CLAUSES*/
/*Top Clauses*/
const addClauseTop = document.querySelector('#addClauseTop');
var targetClauseElement;
var addDetail = document.getElementById('addDetail');
addDetail.addEventListener('focusin', function(e) {
createDetail(e.relatedTarget);
});
window.addEventListener('mouseup',function(e) {
if ( e.currentTarget != addDetail ) {
addDetail.style.display='none';
}
});
var firstTopClause = document.getElementsByClassName('clause')[0];
firstTopClause.addEventListener('click', function(e) {
addDetail.style.display='inline-block';
});
var firstBottomClause = document.getElementsByClassName('clauseDivReverse')[0];
firstBottomClause.addEventListener('click', function(e) {
addDetail.style.display='inline-block';
});
addClauseTop.addEventListener('click',function(e){
e.preventDefault();
//Get Divs-Overlay
const topDivs = document.querySelector('#topClauses');
const bottomDivs = document.querySelector('#bottomClauses');
// Create Elements
const clauseDiv = document.createElement('div');
const clauseText = document.createElement('input');
const clauseStroke = document.createElement('div');
// // //Give Style
clauseDiv.classList.add('clauseDiv');
clauseDiv.addEventListener('click', function(e) {
addDetail.style.display='inline-block';
});
clauseText.classList.add('clause');
clauseText.setAttribute("id", "clause");
clauseStroke.classList.add('strokeClause');
//
// // Append to document
clauseDiv.appendChild(clauseText);
clauseDiv.appendChild(clauseStroke);
topDivs.appendChild(clauseDiv);
document.body.appendChild(topDivs);
document.body.appendChild(bottomDivs);
})
/*BOTTOM Clauses*/
const addClauseBottom = document.querySelector('#addClauseBottom');
addClauseBottom.addEventListener('click',function(e){
e.preventDefault();
//Get Divs-Overlay
const topDivs = document.querySelector('#topClauses');
const bottomDivs = document.querySelector('#bottomClauses');
// Create Elements
const clauseDiv = document.createElement('div');
clauseDiv.addEventListener('click', function(e) {
targetClauseElement = e.currentTarget;
addDetail.style.display='inline-block';
});
const clauseText = document.createElement('input');
const clauseStroke = document.createElement('div');
// // //Give Style
clauseDiv.classList.add('clauseDivReverse');
clauseText.classList.add('clauseReverse');
clauseText.setAttribute("id", "clauseReverse");
clauseStroke.classList.add('strokeClauseReverse');
//
// // Append to document
clauseDiv.appendChild(clauseText);
clauseDiv.appendChild(clauseStroke);
bottomDivs.appendChild(clauseDiv);
document.body.appendChild(bottomDivs);
})
/***********/
//Create a addDetail
function createDetail(target){
var mainColumn = target.parentElement;
var strokeColumn = mainColumn.children[1];
// Create Elements
var levelOneDiv = document.createElement('div');
var levelOneText = document.createElement('input');
if ( mainColumn.classList.contains('clauseDiv') ) {
levelOneDiv.classList.add('levelOneClauseReverse');
levelOneText.classList.add('levelOneTextReverse');
//I thought you have not completed your style yet, like something levelOneClause class
} else {
levelOneDiv.classList.add('levelOneClauseReverse');
levelOneText.classList.add('levelOneTextReverse');
}
levelOneDiv.appendChild(levelOneText);
strokeColumn.appendChild(levelOneDiv);
}
#import url('https://fonts.googleapis.com/css?family=Vollkorn+SC');
body{
margin: 10%;
margin-right: 15%;
margin-left: 10%;
margin-top: 5%;
}
h1{
color: #3B3C3D;
font-family: 'Vollkorn SC', serif;
font-size: 2em;
text-align:center;
}
h2{
color: #3B3C3D;
font-family: 'Vollkorn SC', serif;
font-size: 1.5em;
text-align:center;
}
#bottomClauses{
clear: both;
float: right;
}
/*CONTROL-PANEL*/
#controlPanel{
float: inline-block;
margin-top: 5%;
margin-left: 20%;
margin-right: 20%;
margin-bottom: 15%;
padding-bottom: 2%;
border-radius: 10%;
border-bottom: 0.1vw solid #3B3C3D;
}
.addClause{
background-color: #2c3e50;
margin-top: 5%;
font-size: 0.75em;
padding: 0.5em;
border: 0;
color: #FFF;
}
.addClause:hover{
cursor: pointer;
background-color: #000;
}
.addDetail{
display: none;
background-color: #2c3e50;
margin-top: 5%;
font-size: 0.75em;
padding: 0.5em;
border: 0;
color: #FFF;
}
.addDetail:hover{
cursor: pointer;
background-color: #000;
}
/*FISHBONE*/
#fishBone{
position: relative;
float:right;
top: 19.75vw;
width: 100%;
height: 0.2vw;
background-color: #34495e;
}
#finalResult{
position: absolute;
/*float:right;*/
left: 83.5vw;
top: 44.25vw;
width: 7.5vw;
height: 7.5vw;
padding: 1vw;
text-align: center;
color: #FFF;
background-color: #7f8c8d;
border-radius: 50%;
border: 0.15vw solid #34495e;
}
/*NEW CLAUSE*/
.clauseDiv{
display: inline-block;
float:right;
width: 5vw;
margin-right: 12.5vw;
}
.clause{
float: inline-block;
position: relative;
top: -3.5vw;
right: 2vw;
text-align: center;
width: 5.8vw;
height: 1.5vw;
padding: 0.2vw;
color: #FFF;
background-color: #3498db;
border-radius: 0.15vw;
border: 0;
}
.strokeClause{
position: relative;
top: -5.75vw;
transform: rotate(-25deg);
background-color: #34495e;
width: 0.1vw;
height: 25vw;
margin-left: 7.5vw;
border: 0.05vw solid #34495e;
border-radius: 0.1vw;
float: inline-block;
z-index: -1;
}
/*NEW CLAUSE REVERSE*/
.clauseDivReverse{
float: inline-block;
float:right;
width: 5vw;
margin-right: 12.5vw;
}
.clauseReverse{
position: relative;
top: 15.5vw;
right: 2.5vw;
float: inline-block;
text-align: center;
width: 5.8vw;
height: 1.5vw;
padding: 0.2vw;
color: #FFF;
background-color: #3498db;
border-radius: 0.15vw;
border: 0;
}
.strokeClauseReverse{
position: relative;
top: -9.75vw;
transform: rotate(25deg);
background-color: #34495e;
width: 0.1vw;
height: 25vw;
margin-left: 7.5vw;
border: 0.05vw solid #34495e;
border-radius: 0.1vw;
float: inline-block;
z-index: -1;
}
/*NEW LEVEL ONE*/
.levelOneClauseReverse{
margin-bottom: 5vw;
}
.levelOneTextReverse{
border: 0;
position: relative;
font-size: 0.75vw;
width: 13vw;
top: 4.5vw;
right: 12.75vw;
border-bottom: 0.1vw solid #34495e;
transform: rotate(-25deg);
}
<body>
<h1>Diagram Editor</h1>
<div id='controlPanel'>
<h2>Control Panel</h2>
<input type='submit' name='addClause' value='Clause on TOP' class='addClause' id='addClauseTop'>
<input type='submit' name='addClause' value='Clause on BOTTOM' class='addClause' id='addClauseBottom'>
<input type='submit' name='addClause' value='Add Detail' class='addDetail' id='addDetail'>
</div>
<div id='fishBone'></div>
<input type='text' name='clause' id='finalResult'>
<div id='topClauses'>
<div class='clauseDiv'>
<input class='clause' id='clause'>
<div class='strokeClause'>
</div>
</div>
</div>
<div id='bottomClauses'>
<div class='clauseDivReverse' >
<input class='clauseReverse clause'>
<div class='strokeClauseReverse'>
<div class='levelOneClauseReverse'>
<input class='levelOneTextReverse'>
</div>
<div class='levelOneClauseReverse'>
<input class='levelOneTextReverse'>
</div>
<div class='levelOneClauseReverse'>
<input class='levelOneTextReverse'>
</div>
<div class='levelOneClauseReverse'>
<input class='levelOneTextReverse'>
</div>
</div>
</div>
</div>
<script src="app.js"></script>
</body>

I'm trying to add previous and next arrows to this content slider

Currently there are circles at the bottom that can be used to navigate between slides. I would like to add next and previous arrows to the sides that the user can click on to proceed forwards or back through the slides.
CSS:
#wrapper {
width: 2000px;
position: relative;
left: 0px;
transition: left 0.6s ease-in-out;
}
.content {
float: left;
width: 500px;
height: 300px;
white-space: normal;
background-repeat: no-repeat;
}
#contentContainer {
width: 500px;
height: 300px;
overflow: hidden;
}
#navLinks {
margin-top:-61px;
position:relative;
text-align: center;
width: 500px;
}
#navLinks ul {
margin: 0px;
padding: 0px;
display: inline-block;
margin-top: 6px;
}
#navLinks ul li {
float: left;
text-align: center;
margin: 10px;
list-style: none;
cursor: pointer;
background-color: rgba(204,204,204,0.8);
padding: 10px;
border-radius: 50%;
}
#navLinks ul li:hover {
background-color: #FFF;
}
#navLinks ul li.active {
background-color: rgba(156,227,100,0.9);
color: #FFFFFF;
}
#navLinks ul li.active:hover {
background-color: red;
color:#FFF;
}
#itemOne {
background-image: url("http://telcospace.com/wp-content/uploads/2013/02/android_eating_apple_1000x500_by_crus23-d38bpx9-640x300.jpg");
}
#itemTwo {
background-image: url("http://www.thetimesofhealth.com/wp-content/uploads/2014/08/Angry-Baby-Face-500x300.jpg");
}
#itemThree {
background-image: url("http://animalsugar.com/wp-content/uploads/2014/10/baby-cat-hd-wallpapers-baby-cat-widescreen.jpg");
}
#itemFour {
background-image: url("http://cuteimages.net/data/2015/5/the-first-puppy-to-leave-me-speechless-name-cuteimages.net.png");
}
HTML:
<div id="contentContainer">
<div id="wrapper">
<div id="itemOne" class="content">
</div>
<div id="itemTwo" class="content">
</div>
<div id="itemThree" class="content">
</div>
<div id="itemFour" class="content">
</div>
</div>
</div>
<div id="navLinks">
<ul>
<li class="itemLinks" data-pos="0px"></li>
<li class="itemLinks" data-pos="-500px"></li>
<li class="itemLinks" data-pos="-1000px"></li>
<li class="itemLinks" data-pos="-1500px"></li>
</ul>
</div>
JavaScript:
var links = document.querySelectorAll(".itemLinks");
var wrapper = document.querySelector("#wrapper");
var activeLink = 0;
for (var i = 0; i < links.length; i++) {
var link = links[i];
link.addEventListener('click', setClickedItem, false);
link.itemID = i;
}
links[activeLink].classList.add("active");
function setClickedItem(e) {
removeActiveLinks();
resetTimer();
var clickedLink = e.target;
activeLink = clickedLink.itemID;
changePosition(clickedLink);
}
function removeActiveLinks() {
for (var i = 0; i < links.length; i++) {
links[i].classList.remove("active");
}
}
function changePosition(link) {
link.classList.add("active");
var position = link.getAttribute("data-pos");
wrapper.style.left = position;
}
var timeoutID;
function startTimer() {
timeoutID = window.setInterval(goToNextItem, 2963);
}
startTimer();
function resetTimer() {
window.clearInterval(timeoutID);
startTimer();
}
function goToNextItem() {
removeActiveLinks();
if (activeLink < links.length - 1) {
activeLink++;
} else {
activeLink = 0;
}
var newLink = links[activeLink];
changePosition(newLink);
}
Here is the JSFiddle http://jsfiddle.net/stormbloom/2d0a1215/
I would like to learn this for personal experience, otherwise I would just use a plugin like WowSlider. If it's easier to do this by building a new slider from scratch then any links to resources explaining how to accomplish this would also be appreciated.
This is an approach with arrows, just tweak with the design.
In the HTML I added the correspoding arrows, and in the JS I added the EventListeners and the function goToPreviousItem() at the end.
var links = document.querySelectorAll(".itemLinks");
var wrapper = document.querySelector("#wrapper");
document.querySelector('#previous').addEventListener('click', goToPreviousItem, false);
document.querySelector('#next').addEventListener('click', goToNextItem, false);
var activeLink = 0;
for (var i = 0; i < links.length; i++) {
var link = links[i];
link.addEventListener('click', setClickedItem, false);
link.itemID = i;
}
links[activeLink].classList.add("active");
function setClickedItem(e) {
removeActiveLinks();
resetTimer();
var clickedLink = e.target;
activeLink = clickedLink.itemID;
changePosition(clickedLink);
}
function removeActiveLinks() {
for (var i = 0; i < links.length; i++) {
links[i].classList.remove("active");
}
}
function changePosition(link) {
link.classList.add("active");
var position = link.getAttribute("data-pos");
wrapper.style.left = position;
}
var timeoutID;
function startTimer() {
timeoutID = window.setInterval(goToNextItem, 2963);
}
//startTimer();
function resetTimer() {
window.clearInterval(timeoutID);
startTimer();
}
function goToNextItem() {
removeActiveLinks();
if (activeLink < links.length - 1) {
activeLink++;
} else {
activeLink = 0;
}
var newLink = links[activeLink];
changePosition(newLink);
}
function goToPreviousItem() {
removeActiveLinks();
if(activeLink == 0) {
activeLink = links.length - 1;
} else {
activeLink--;
}
var newLink = links[activeLink];
changePosition(newLink);
}
#wrapper {
width: 2000px;
position: relative;
left: 0px;
transition: left 0.6s ease-in-out;
}
.content {
float: left;
width: 500px;
height: 300px;
white-space: normal;
background-repeat: no-repeat;
}
#outsideContainer {
width: 600px;
}
#previous {
width: 50px;
display: inline-block;
text-align: center;
float: left;
margin-top: 150px;
}
#next {
width: 50px;
display: inline-block;
text-align: center;
float: right;
margin-top: 150px;
}
#contentContainer {
width: 500px;
height: 300px;
overflow: hidden;
display: inline-block;
}
#navLinks {
margin-top:-61px;
position:relative;
text-align: center;
width: 600px;
}
#navLinks ul {
margin: 0px;
padding: 0px;
display: inline-block;
margin-top: 6px;
}
#navLinks ul li {
float: left;
text-align: center;
margin: 10px;
list-style: none;
cursor: pointer;
background-color: rgba(204,204,204,0.8);
padding: 10px;
border-radius: 50%;
border:rgba(255,255,255,0.9) 1px solid;
box-shadow: 0 0 4px #fff;
}
#navLinks ul li:hover {
background-color: #FFF;
box-shadow: 0 0 10px #fff;
border:rgba(255,255,255,0.6) 1px solid;
}
#navLinks ul li.active {
background-color: rgba(156,227,100,0.9);
color: #FFFFFF;
outline-width: 1px;
}
#navLinks ul li.active:hover {
background-color: rgba(255,255,255,0.7);
color: #FFFFFF;
box-shadow: 0 0 10px #fff;
border:rgba(255,255,255,0.9) 1px solid;
}
#itemOne {
background-color: #000;
background-image: url("http://telcospace.com/wp-content/uploads/2013/02/android_eating_apple_1000x500_by_crus23-d38bpx9-640x300.jpg");
}
#itemTwo {
background-color: #fff;
background-image: url("http://www.thetimesofhealth.com/wp-content/uploads/2014/08/Angry-Baby-Face-500x300.jpg");
}
#itemThree {
background-color: #fff;
background-image: url("http://animalsugar.com/wp-content/uploads/2014/10/baby-cat-hd-wallpapers-baby-cat-widescreen.jpg");
}
#itemFour {
background-color: #fff;
background-image: url("http://images5.fanpop.com/image/photos/28100000/Katy-Perry-gifs-katy-perry-28147211-500-300.gif");
}
<div id="outsideContainer">
<div id="previous"><<</div>
<div id="contentContainer">
<div id="wrapper">
<div id="itemOne" class="content"></div>
<div id="itemTwo" class="content"></div>
<div id="itemThree" class="content"></div>
<div id="itemFour" class="content"></div>
</div>
</div>
<div id="next">>></div>
</div>
<div id="navLinks">
<ul>
<li class="itemLinks" data-pos="0px"></li>
<li class="itemLinks" data-pos="-500px"></li>
<li class="itemLinks" data-pos="-1000px"></li>
<li class="itemLinks" data-pos="-1500px"></li>
</ul>
</div>

Jquery scrollbar hides elements in menu

I dont want my li list to disappear while the new menu (menu.fixed) appears! I just want'em to follow the fixed menu down! how do i fix this? Here is the jquery:
var menuTop = $('.menu').offset().top;
var menuClone = $('.menu').clone().addClass('fixed');
$(window).bind('scroll', function() {
var scrollY = window.pageYOffset;
if(scrollY > menuTop) {
if(menuClone.parent().length === 0) {
menuClone.appendTo($('.menu').parent());
}
} else if(menuClone.parent().length > 0) {
menuClone.remove();
}
});
And this the relevant css:
.menu {
background-color: white;
width: 80%;
height: 50px;
font-size: 1.5em;
font-family: Roboto;
margin-bottom:0px;
margin-left:10%;
border-bottom: 2px solid #756B6B;
}
.menu.fixed {
position: fixed;
left: 0;
top: 0;
height: 50px;
width:76.8%;
margin-left: 11.55%;
border-bottom: 2px solid #756B6B ;
}
li {
float: right;
margin-left:40px;
list-style: none;
position:relative;
padding-bottom: 10px;
}
and the html
<div class="menu">
<ul>
<li id="sistaord">ovrigt</li>
<li id="jobberfarenhet">Jobberfarenhet</li>
<li>Utbildning</li>
</ul>
</div>
Probably you don't need to clone menu. You only need to switch class "fixed" for the menu element:
HTML the same,
CSS:
.menu {
background-color: white;
width: 80%;
height: 50px;
font-size: 1.5em;
font-family: Roboto;
margin-bottom:0px;
margin-left:10%;
padding-bottom: 10px;
border-bottom: 2px solid #756B6B;
}
.menu.fixed {
position: fixed;
left: 0;
top: 0;
}
li {
float: right;
margin-left:40px;
list-style: none;
}
JS:
var menu = $('.menu');
var menuTop = menu.offset().top;
$(window).bind('scroll', function() {
var scrollY = window.pageYOffset;
if (scrollY > menuTop) {
if (!menu.data('fixed')) {
menu.addClass('fixed').data('fixed', true);
}
} else if (menu.data('fixed')) {
menu.removeClass('fixed').data('fixed', false);
}
});
Here is a demo

Categories