Pure JS add class to only one of recurring elements - javascript

I'm trying to toggle a div's class in pure javascript (unfortunately I cannot use jQuery). I've got some code working but it doesn't work for multiple instances of the div and I'd appreciate some help for that.
I can't give each element it's own specific ID, so I'd need a way to target only the div with a class of 'truncate' that is the parent of the particular button that is clicked. Currently I have hidden the results by default and am just toggling the 'show' class
<div class="truncate">
<div class="result">Result 1</div>
<div class="result">Result 2</div>
<div id="button">Show more</div>
</div>
collapse= document.getElementById('button');
collapse.onclick = function() {
collapse.parentElement.classList.toggle("show");
};
/* HIDE PLATES BY DEFAULT */
.truncate .result {
display: none;
}
/* SHOW RESULTS WHEN SHOW CLASS APPLIED */
.truncate.show .result {
display: block !important;
}
Thank you - help appreciated as always.

I think you need getElementsByClassName
(function() {
var collapse = document.getElementsByClassName('button');
for (var elIndex = 0; elIndex < collapse.length; elIndex++) {
collapse[elIndex].onclick = function() {
this.parentElement.classList.toggle("show");
};
}
})();
/* HIDE PLATES BY DEFAULT */
.truncate .result {
display: none;
}
/* SHOW RESULTS WHEN SHOW CLASS APPLIED */
.truncate.show .result {
display: block !important;
}
<div class="truncate">
<div class="result">Result 1</div>
<div class="result">Result 2</div>
<div class="button">Show more</div>
</div>
<div class="truncate">
<div class="result">Result 1</div>
<div class="result">Result 2</div>
<div class="button">Show more</div>
</div>
<div class="truncate">
<div class="result">Result 1</div>
<div class="result">Result 2</div>
<div class="button">Show more</div>
</div>

You should replace the id of Show more to class.
And use the following code.
collapse =document.getElementsByClassName('button');
for(let i = 0; i < collapse.length; i++){
let oneElement = collapse[i];
oneElement.addEventListener('click', function() {
oneElement.parentElement.classList.toggle("show");
})
}

Parse (loop over) all of your div.truncate elements and give themselves their own functionality via the Accordionize Function.
const Accordionize = el => {
const results = el.querySelectorAll('.result')
const toggleButton = el.querySelector('button')
let open = false
const _toggle = () => {
const action = open ? 'remove' : 'add'
results.forEach(item => item.classList[action]('show'))
open = !open
}
toggleButton.addEventListener('click', _toggle)
}
// get all div.truncate and apply them to their own instance of Accordionize
document.querySelectorAll('.truncate').forEach(Accordionize)
.truncate {
border: 2px solid red;
margin: 5
}
.result {
display: none;
}
.show {
display: block
}
<div class="truncate">
<div class="result">Result 1</div>
<div class="result">Result 2</div>
<button>Show more1</button>
</div>
<div class="truncate">
<div class="result">Result 3</div>
<div class="result">Result 4</div>
<button>Show more2</button>
</div>
<div class="truncate">
<div class="result">Result 5</div>
<div class="result">Result 6</div>
<button>Show more3</button>
</div>
<div class="truncate">
<div class="result">Result 7</div>
<div class="result">Result 8</div>
<button>Show more4</button>
</div>

Related

Cannot get value of div

I have problem with getting value of a div with class="idC". I need this value to remove object from my array. I know I probably gonna need to use parseInt but all I'm getting with this code is rowid: undefined when I use console.log("rowid: " + bikeId.value). bikeRow.remove(); works fine. It removes the row I want to.
const buttonDel = document.querySelectorAll(".deleteC");
buttonDel.forEach(button => {
console.log("jazda");
button.addEventListener('click', () => {
const bikeRow = button.parentNode;
const bikeId = bikeRow.firstChild;
if (!window.confirm())
return;
console.log("rowid: " + bikeId.value);
bikeRow.remove();
//bikeStorage.removeBike(bikeId.value);
})
})
<div class="bikeRows">
<div class="bikeRow">
<div class="idC"></div>${bike.id}</div>
<div class="frameC">${bike.frame}</div>
<div class="suspC">${bike.susp}</div>
<div class="wheelC">${bike.wheel}</div>
<div class="typeC">${bike.constructor.name}</div>
<div class="deleteC"><button class="delButton" id="${bike.id}">Delete</button></div>
</div>
</div>
You have invalid HTML and you really should delegate
I added the ID as a data-attribute to the row like this
<div class="bikeRow" data-id="${bike.id}">
Makes the code much simpler to debug and extend
document.querySelector(".bikeRows").addEventListener("click", e => {
const tgt = e.target.closest("button");
if (!tgt.matches(".delButton")) return; // not a delete button
if (!window.confirm("Sure?")) return; // they cancelled
const bikeRow = tgt.closest("div.bikeRow"),
id = bikeRow.dataset.id; // the ID to remove from the storage
bikeRow.remove();
//bikeStorage.removeBike(id);
})
<div class="bikeRows">
<div class="bikeRow" data-id="ID1">
<div class="idC">ID1</div>
<div class="frameC">Frame 1</div>
<div class="suspC">Susp 1</div>
<div class="wheelC">Wheel 1</div>
<div class="typeC">Constructor name 1</div>
<div class="deleteC"><button class="delButton">Delete</button></div>
</div>
<div class="bikeRow" data-id="ID2">
<div class="idC">ID 2</div>
<div class="frameC">Frame 2</div>
<div class="suspC">Susp 2</div>
<div class="wheelC">Wheel 2</div>
<div class="typeC">Constructor name 2</div>
<div class="deleteC"><button class="delButton">Delete</button></div>
</div>
<div class="bikeRow" data-id="ID3">
<div class="idC">ID 3</div>
<div class="frameC">Frame 3</div>
<div class="suspC">Susp 3</div>
<div class="wheelC">Wheel 3</div>
<div class="typeC">Constructor name 3</div>
<div class="deleteC"><button class="delButton">Delete</button></div>
</div>
</div>

Show a random div upon click except the current one

I made a simple quote slider that changes the sentence on the screen randomly upon each click, but I don't want it to show the same quote twice in a row. How can I exclude the current quote from the Math.random algorithm and make the slider show any other quote upon each click?
(I don't want each quote to be shown only once, I just want to prevent the slider to show the same one in a row)
HTML:
<div class="container" onclick="changequote()">
<div class="quote">Sentence 1</div>
<div class="quote">Sentence 2</div>
<div class="quote">Sentence 3</div>
</div>
<script>window.onload = changequote()</script>
JS:
function changequote() {
var random = Math.floor(Math.random() * $('.quote').length);
$('.quote').hide().eq(random).fadeTo(500, 1);
}
CSS:
.quote {
display: none;
}
You could toggle a class to track the current quote. Then randomly pick from the quotes that are :not(.current).
Also I moved the javascript to the javascript section, which really helps for maintainability. Nothing like pouring through the .js file when debugging just to find out the issue is originating from the html.
function changequote() {
let $quotes = $('.quote:not(.current)');
$('.quote').removeClass('current').hide(); //reset all quotes
$quotes //pick from all quotes except the previously selected one
.eq(Math.floor(Math.random() * $quotes.length))
.addClass('current')
.fadeIn();
}
$('.container').on('click', changequote).click(); //click will initialize on page load
.quote{
cursor: pointer;
display: none;}
<div class="container">
<div class="quote">Sentence 1</div>
<div class="quote">Sentence 2</div>
<div class="quote">Sentence 3</div>
<div class="quote">Sentence 4</div>
<div class="quote">Sentence 5</div>
<div class="quote">Sentence 6</div>
<div class="quote">Sentence 7</div>
<div class="quote">Sentence 8</div>
<div class="quote">Sentence 9</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Just save the index into a global variable, using closures
const changeQuote = (() => {
let lastSelectedIndex;
return function() {
let random = Math.floor(Math.random() * $('.quote').length);
while(true)
{
random = Math.floor(Math.random() * $('.quote').length);
if(random !== lastSelectedIndex) break;
}
$('.quote').eq(lastSelectedIndex).hide();
$('.quote').eq(random).fadeIn(500);
lastSelectedIndex = random;
}
})();
EDIT: Here is a running example
const changeQuote = (() => {
let lastSelectedIndex;
return function() {
let random = Math.floor(Math.random() * $('.quote').length);
while(true)
{
random = Math.floor(Math.random() * $('.quote').length);
if(random !== lastSelectedIndex) break;
}
$('.quote').eq(lastSelectedIndex).hide();
$('.quote').eq(random).fadeIn(500);
lastSelectedIndex = random;
}
})();
.quote {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="quote">Sentence 1</div>
<div class="quote">Sentence 2</div>
<div class="quote">Sentence 3</div>
<button onclick="changeQuote()">Show Random Quote</button>

How to toggle/switch the classes between three or more divs in a sequence?

How can I easily toggle/switch the classes between three or more divs in a sequence by click?
Example html:
<div class="box">Box 1</div>
<div class="box active">Box 2</div>
<div class="box">Box 3</div>
<div class="next">Next</div>
<div class="back">Back</div>
This way just works with two:
$(".next, .back").click(function(){
$(".box").toggleClass("active");
});
Simply to check if nth-child has the active class and loop.
$(".next").click(function(){
$(".box").each( function(i, j) {
if( $(this).hasClass('active') ) {
$(this).removeClass('active');
$(".box:nth-child("+(((i+1)%$(".box").length)+1)+")").addClass('active');
return false;
}
});
});
$(".back").click(function(){
$(".box").each( function(i, j) {
if( $(this).hasClass('active') ) {
$(this).removeClass('active');
$(".box:nth-child("+(((i-1)+$(".box").length)%$(".box").length+1)+")").addClass('active');
return false;
}
});
});
.active {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<div class="box">Box 1</div>
<div class="box active">Box 2</div>
<div class="box">Box 3</div>
<div class="back">Back</div>
<div class="next">Next</div>
</div>
This is pretty generic
$(".nav").on("click", function() {
var dir = $(this).is(".next") ? 1 : -1; // which direction are we going?
var active = $(".box.active").index() - 1;
var $boxes = $(".box");
active += (1 * dir);
if (active < 0) active = $boxes.length - 1; // wrap
else if (active >= $boxes.length) active = 0;
$(".box").removeClass("active");
$(".box").eq(active).addClass("active");
});
.active {
color: red
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="box">Box 1</div>
<div class="box active">Box 2</div>
<div class="box">Box 3</div>
<br/>
<div class="nav back">Back</div>
<div class="nav next">Next</div>
I've created another solution that gets the button's ID (which I've added) and uses that to dictate where to go.
var box = $('.box');
var maxBoxes = box.length;
$("#nextBtn, #backBtn").click(function() {
var getBtn = $(this).get(0).id,
activeBox = $('.box.active'),
position = activeBox.index();
activeBox.removeClass('active');
if (getBtn === 'nextBtn') {
(position == maxBoxes) ? box.eq(0).addClass('active'): activeBox.next().addClass('active');
} else {
(position === 1) ? box.last().addClass('active'): activeBox.prev().addClass('active');
}
});
.active {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="box">Box 1</div>
<div class="box">Box 2</div>
<div class="box active">Box 3</div>
<div id="nextBtn" class="next">Next</div>
<div id="backBtn" class="back">Back</div>
I think that the following should be efficient, because it will not do unnecessary checks.
var last = $(".active")
function toggle(dir){
var future = last[dir]();
if(!(future.length && future.hasClass('box'))) {
return;
}
last.toggleClass("active")
last = future
last.toggleClass("active");
}
$(".next").click(toggle.bind(void 0, 'next'));
$(".back").click(toggle.bind(void 0, 'prev'));

Controlling Javascript Selector

The following codes makes div appear sequentially.
$(document).ready(function() {
$('.word1, .word2, .word3').each(function(fadeIn) {
$(this).delay(fadeIn * 500).fadeIn(1000);
});
});
.chat {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="chat word1">Word 1</div>
<div class="chat word2">Word 2</div>
<div class="chat word3">Word 3</div>
<div id="" class="">Word 4</div>
</body>
What I want to do is, I don't want it to appear in a sequence. I can do it by simply replacing elements in an html, for example I can do:
<div class="chat word2">Word 2</div>
<div class="chat word1">Word 1</div>
<div class="chat word3">Word 3</div>
However, I don't want to change anything on the html elements. I want to do it using javascript. At first, I thought javascript selector works like an array and I can replace
$('.word1, .word2, .word3') with $('.word2, .word1, .word3')
but it does not seems to work that way.
Is there a way to do this with Javascript?
Here be a solution if you do not want to change your HTML(and incase css also):
Keep the shuffle Position in array.
Iterate all div having class chat.
Put the DOM element in new array based on shuffle Position.
Iterate all element of new array and append in body.
$(document).ready(function() {
var shufflePosition=[1,0,2];//Keep the shufflePosition in array
var result=[];
//Iterate all div having class chat
$('.chat').get().forEach(function(entry, index, array) {
result[index]=array[shufflePosition[index]];
});
for (var i = result.length-1; i >= 0; i--) {
$( "body" ).last().prepend(result[i]);
//$(result[i]).show();
$(result[i]).delay(i*500).fadeIn(1000);
}
});
.chat {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="chat word1">Word 1</div>
<div class="chat word2">Word 2</div>
<div class="chat word3">Word 3</div>
<div id="" class="">Word 4</div>
</body>
You use a query selector:
var word1 = document.querySelectorAll(".chat", ".word1")[0];
This selects the first element with both classes .chat and .word1.
how about this
$(document).ready(function() {
$('.chat').delay(500).fadeIn(1000);
});
.chat {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="chat word1">Word 1</div>
<div class="chat word2">Word 2</div>
<div class="chat word3">Word 3</div>
<div id="" class="">Word 4</div>
</body>
I think the simplest solution, to not care about the order of the Divs, is:
$('.chat').each(function(fadeIn) {
$(this).delay(fadeIn * 500).fadeIn(1000);
});
You should define a common class for these randomly ordered elements, or wrap them with a parent element, eg:
$('.randomlysortedelements div').each(function(fadeIn) {
$(this).delay(fadeIn * 500).fadeIn(1000);
});
<body>
<div class="randomlysortedelements">
<div class="chat word3">Word 3</div>
<div class="chat word1">Word 1</div>
<div class="chat word2">Word 2</div>
</div>
<div id="" class="">Word 4</div>
</body>
You can shuffle your array length and prependTo to word4 something like this:
$(document).ready(function() {
elements = $('.word1, .word2, .word3');
let arrayData = [];
for(i=0;i<elements.length;i++){
arrayData.push(i);
}
shuffleArray(arrayData);
for(i=0;i<arrayData.length;i++){
$("body:last").prepend(elements.eq(arrayData[i]));
elements.eq(arrayData[i]).show()
}
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
});
.chat {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="chat word1">Word 1</div>
<div class="chat word2">Word 2</div>
<div class="chat word3">Word 3</div>
<div id="" class="word4">Word 4</div>
</body>

Display div when clicking on another div

I've added three pictures. Look at them please.
What is the best solution to create something like this? I would create after each row a big container and this container is collapsed. After clicking on one of the 3 overlying containers I would fill the container with the text and show it. But what happens when the display can't show 3 divs in a row, because I will use flex boxes? Is there a better solution with much less jquery?
Maybe something like this is a good place to start:
https://jsfiddle.net/547ec3bx/
HTML
<div class="wrapper">
<div class="row">
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
<div class="row">
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
<div class="row">
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
</div>
Javascript
document.querySelectorAll('.row').forEach((element, index) => {
element.style.order = index * 2;
});
document.querySelectorAll('.element').forEach(element => {
element.addEventListener('click', event => {
var newRow = document.createElement('div');
newRow.classList.add('row');
newRow.style.order = +event.currentTarget.parentNode.style.order + 1;
var newElement = document.createElement('div');
newElement.classList.add('element');
newRow.appendChild(newElement);
event.currentTarget.parentNode.parentNode.appendChild(newRow);
});
});
CSS
.element {
min-width: 100px;
height: 50px;
flex: 1;
border: 1px solid black;
flex-wrap: nowrap;
}
.row {
width: 350px;
display: flex;
flex-direction: row;
}
.wrapper {
display: flex;
flex-direction: column;
}
you can use javascript to solve this problem , like this ....
html code:
<div id="a">
<h3>wellcome</h3>
</div>
<div id="b">
<h3>hello...</h3>
</div>
javascript code in external file
function goB()
{
document.getElementById("a").style.display="none";
document.getElementById("b").style.display="block";
}
function
{
document.getElementById("b").style.display="none";
document.getElementById("a").style.display="block";
}
Add a div and set its display to Hidden.
Get onclick event for a particular div and set the display property to block
window.addEventListener("load", function(){
document.getElementById("click").onclick = function(){
document.getElementById("div-1").style.display = "block";
};
});
.row
{
width:100%;
}
.one-third
{
width:33.33333%;
float:left;
padding:30px 0;
}
.full-width
{
display:none;
width:100%;
text-align:center;
}
<div class=wrap>
<div class="row">
<div id="click" class="one-third">
Column 1-Click Me
</div>
<div class="one-third">
Column 2
</div>
<div class="one-third">
Column 3
</div>
</div>
<div class="full-width" id="div-1">Full width Div</div>
<div class="row">
<div class="one-third">
Column 1
</div>
<div class="one-third">
Column 2
</div>
<div class="one-third">
Column 3
</div>
</div>

Categories