Add class to matching element without other specific class - javascript

Whenever a user clicks on the body I would like to add a class to a certain element, as long as that element doesn't have a specific class. The issue is, I re-use this element and some of these elements will have that specific class I mentioned and other will not. If one element has this class, with my current code, no element will have new class added.
Here is a fiddle showing the behaviour.
Example:
$('body').on('click', function(){
if ($('.box').hasClass('red') && !$('.box').hasClass('stay-red')) {
$('.box').addClass('blue');
}
});
html, body {
background: lightblue;
height: 100%;
}
.box {
height: 20px;
width: 20px;
margin-bottom: 10px;
}
.red {
background: red;
}
.blue {
background: blue;
}
<div class="box red stay-red"></div>
<div class="box red"></div>

It will be a lot easier with filter, and will avoid your problem:
$('body').on('click', function(){
$('.box').filter('.red:not(.stay-red)').addClass('blue');
});
html, body {
background: lightblue;
height: 100%;
}
.box {
height: 20px;
width: 20px;
margin-bottom: 10px;
}
.red {
background: red;
}
.blue {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<body>
<div class="box red stay-red"></div>
<div class="box red"></div>
</body>
</html>

$('.box.red:not(.stay-red)').addClass('blue');
Is that what you want?
:not() Selector https://api.jquery.com/not-selector/
https://jsfiddle.net/7L3ub1sp/

$(function(){
$('body').on('click', function(){
$('.box').each(function(){
if ($(this).hasClass('red') && !$(this).hasClass('stay-red')) {
$(this).addClass('blue');
}
})
});
})
html, body {
background: lightblue;
height: 100%;
}
.box {
height: 20px;
width: 20px;
margin-bottom: 10px;
}
.red {
background: red;
}
.blue {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<body>
<div class="box red stay-red"></div>
<div class="box red"></div>
</body>
</html>

You can use:
$('body').on('click', function(){
$('.box.red:not(.stay-red)').addClass('blue');
});
Or loop through all of them with each:
$('body').on('click', function(){
$('.box').each(function() {
if ($(this).hasClass('red') && !$(this).hasClass('stay-red')) {
$(this).addClass('blue');
}
});
});

If you want to avoid adding the new class to all elements if one of them has the other class, you can use some (or every):
var els = document.getElementsByClassName('box');
if(![].some.call(els, function(el) {
return el.classList.contains('stay-red');
}) [].forEach.call(els, function(el) {
return el.classList.add('blue');
});

Here is the body onclick you need:
$('body').on('click', function(){
$('.box.red:not(.stay-red)').removeClass('red').addClass('blue');
});
You also need to remove the class .red, even if in this precise case it works because the class .blue is defined after the class .red in the CSS

Related

Show/hide div or image when scrolling

Is there a way to show an image or a div when scrolling down a web page and hide it when not scrolling and vice versa?
So in the code below the red div would be displayed when not scrolling, and the green div would be displayed only when scrolling.
.square {
position: fixed;
width: 100px;
height: 100px;
}
.green {
background: green;
display: none;
}
.red {
background: red;
}
.container {
width: 100%;
height: 3000px;
}
<div class="container">
<div class="square green"></div>
<div class="square red"></div>
</div>
The end goal is to achieve something like this: https://mailchimp.com/annual-report/ where the character appears to be walking when the user scrolls, and stands still when the user stops. Is this easily achievable?
You just need an eventListener that listen to a scroll event. However this has the issue that it only recoginze when you scroll but not when you stop scrolling. For that you can use this answer that explains how to listen for a "scroll-stop"
To make the code shorter and easier, I removed your display: none from the green box. I added a new class d-none that contains this proeprty now instead. By default it is added to the green box.
With classList.toggle('d-none') I can toggle class within both boxes which makes it easier then to address and then add or remove the class for every box on its own.
var timer = null;
var box = document.querySelectorAll('.square');
window.addEventListener('scroll', function() {
if (timer !== null) {
clearTimeout(timer);
} else {
box.forEach(el => el.classList.toggle('d-none'));
}
timer = setTimeout(function() {
box.forEach(el => el.classList.toggle('d-none'));
}, 150);
}, false);
.d-none {
display: none;
}
.square {
position: fixed;
width: 100px;
height: 100px;
}
.green {
background: green;
/* display: none; */
/* removed */
}
.red {
background: red;
}
.container {
width: 100%;
height: 3000px;
}
<div class="container">
<div class="square green d-none"></div>
<div class="square red"></div>
</div>
You just need a setTimeout function:
(function($) {
$(function() {
$(window).scroll(function() {
$('.square.red').show()
$('.square.green').hide()
clearTimeout($.data(this));
$.data(this, setTimeout(function() {
$('.square.red').hide()
$('.square.green').show()
}, 250));
});
});
})(jQuery);
.square {
position: fixed;
width: 100px;
height: 100px;
}
.green {
background: green;
}
.red {
background: red;
display: none;
}
.container {
width: 100%;
height: 3000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="square green"></div>
<div class="square red"></div>
</div>

Select the parent of the parent of an element

I want to select the parent of the parent of a child in Javascript without chaining the same method twice: child.parentElement.parentElement.Is there a method for this? The element I want to select is parent1.
The code is just to illustrate the problem, but all I want is to know if there is a method that can substitute the .parentElement.parentElement. I need to select it like this because my code is introduced dinamically into the page.
This is the code to illustrate the problem:
const body = document.querySelector('body');
body.querySelector('button').addEventListener('click', function() {
this.parentElement.parentElement.classList.toggle('black');
});
.parent1 {
background: yellow;
padding: 20px;
}
.parent2 {
background: blue;
padding: 20px;
}
.black {
background: black;
}
<div class="parent1">
<div class="parent2">
<button>Click</button>
</div>
</div>
You can use Element.closest() to find the first parent element that matches a selector, in our case, .parent1:
const body = document.querySelector('body');
body.querySelector('button').addEventListener('click', function() {
this.closest('.parent1').classList.toggle('black');
});
.parent1 {
background: yellow;
padding: 20px;
}
.parent2 {
background: blue;
padding: 20px;
}
.black {
background: black;
}
<div class="parent1">
<div class="parent2">
<button>Click</button>
</div>
</div>

jQuery toggle between two ID's

Why does the following code not work? The red square becomes green but on a second click doesn't become red again.
jQuery(document).ready(function($) {
$("#red").click(function() {
$(this).attr("id", "green");
});
$("#green").click(function() {
$(this).attr("id", "red");
});
});
div {
margin: 0 auto;
width: 100px;
height: 100px;
}
#red {
background-color: red;
}
#green {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="red">
See also: https://codepen.io/thomasmalley/pen/OqWNaM
The issue is because you assign the event handler on load, before the #green element exists.
To fix this you need to use delegated event handlers so that the element selector is evaluated when the event occurs:
jQuery(function($) {
$(document).on('click', "#red", function() {
$(this).attr("id", "green");
});
$(document).on('click', "#green", function() {
$(this).attr("id", "red");
});
});
div {
margin: 0 auto;
width: 100px;
height: 100px;
}
#red {
background-color: red;
}
#green {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="red"></div>
That being said, it's not great practice to be changing id attributes at runtime. They should be static. A much better idea would be to toggle a class on the element instead, which governs the styling.
jQuery(function($) {
$('#foo').click(function() {
$(this).toggleClass('green');
});
});
#foo {
margin: 0 auto;
width: 100px;
height: 100px;
background-color: red;
}
#foo.green {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo"></div>
First, there is div with id red and after clicking that div it switches id to green that is dynamically so in this case we use event-delegation. Try below code -
jQuery(document).ready(function($) {
$(".parent").on('click', '#red', function() {
$(this).attr("id", "green");
});
$(".parent").on('click', '#green', function() {
$(this).attr("id", "red");
});
});
div {
margin: 0 auto;
width: 100px;
height: 100px;
}
#red {
background-color: red;
}
#green {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
<div id="red"></div>
</div>
This is happening because when you load the page there is no element with the id green for a click event to be added to.
Instead, you can use event delegation by using:
$(document).on('click', '#red', function() {...}
and
$(document).on('click', '#green', function() {...}
This way, your click event will be applied to the element with the id green.
See working example below:
jQuery(document).ready(function($) {
$(document).on('click', '#red', function() {
$(this).attr("id", "green");
});
$(document).on('click', '#green', function() {
$(this).attr("id", "red");
});
});
div {
margin: 0 auto;
width: 100px;
height: 100px;
}
#red {
background-color: red;
}
#green {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="red"></div>
Since the id is added dynamically, the code $("#green").click(function() { when loaded will not find element with id green so the click event is not set for that element. Thus you can add a listener on document level:
jQuery(document).ready(function($) {
$(document).on('click', 'div', function(){
var id = $(this).attr('id');
if(id === 'red'){
$(this).attr("id", "green");
} else {
$(this).attr("id", "red");
}
});
});
div {
margin: 0 auto;
width: 100px;
height: 100px;
}
#red {
background-color: red;
}
#green {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="red">
change script
$(document).on('click','#red',function() {
$('#red').attr("id", "green");
});
$(document).on('click','#green',function() {
$('#green').attr("id", "red");
});

Toggle background color of same div

I am trying to toggle the background color of same div.
It does changes once (from blue to red) as expected.
But it is not able to toggle back to red and continue toggling between the 2 colors. I know I should use "==" in the first if-statement but when using "==" not even the first toggle works.
Any suggestions how to get the toggle to work repetitive?
function toggleFunction() {
var x = document.getElementById("box");
if (x.style.background == "blue") {
x.style.background = "red";
} else {
x.style.background = "blue";
}
}
.box {
background-color: blue;
width: 100px;
height: 100px;
margin: 30px 0px 0px 30px;
}
<div id="box" class="box" onclick="toggleFunction()"></div>
The simplest solution would to create a new class called red and toggle that using classList.toggle. The main advantage of this approach would be that you can toggle more CSS properties, if you use a class for toggling and this will also deduct the if-else comparison for you.
function toggleFunction() {
var x = document.getElementById("box");
x.classList.toggle("red");
}
.box {
background-color: blue;
width: 100px;
height: 100px;
margin: 30px 0px 0px 30px;
}
.red{
background-color: red;
}
<div id="box" class="box" onclick="toggleFunction()"></div>
$( ".box" ).each(function() {
$( this).click(function() {
$( this ).toggleClass( "red" );
});
});
.box {
background: blue;
width: 100px;
height: 100px;
margin: 30px 0px 0px 30px;
}
.box.red {
background:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="box" class="box"></div>
<div id="box" class="box"></div>

with javascript onclick add classname to a div

I want to achieve with javascript something like when i clink on any of thumbnail (btn-1, btn-2 and btn-3) the specific class should be add to box div dynamically.
my code: JSFiddle
document.getElementById('btn-1').onclick = function() {
document.getElementById('box').className = 'bg-1';
}
#box {
background-color: darkgray;
width: 200px;
height: 200px;
}
.thumbnail {
width: 30px;
height: 30px;
border: 1px solid;
margin: 5px;
position: relative;
float: left;
}
#btn-1 {
background-color: red;
}
#btn-2 {
background-color: green;
}
#btn-3 {
background-color: blue;
}
.bg-1 {
background-color: red;
}
.bg-2 {
background-color: blue;
}
.bg-3 {
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box"></div>
<div class="thumbnail" id="btn-1"></div>
<div class="thumbnail" id="btn-2"></div>
<div class="thumbnail" id="btn-3"></div>
You javascript is working, but your CSS isn't.
You need to add !important as follows to .bg-1, .bg-2 and .bg-3
.bg-1 {
background-color: red !important;
}
Otherwise the id styling is taking preference over the class styling
You can see the classname is being added if you right click on the grey div and choose inspect element in Chrome.
Instead of bothering with classes, use simply a data- attribute like: data-bg="#f00"
$('[data-bg]').css('background', function () {
$(this).on('click', () => $('#box').css('background', this.dataset.bg));
return this.dataset.bg;
});
#box {
background: darkgray;
width: 120px; height: 120px;
}
[data-bg] {
width: 30px; height: 30px;
margin: 5px;
float: left;
}
<div id="box"></div>
<div data-bg="red"></div>
<div data-bg="#00f"></div>
<div data-bg="rgb(255,0,180)"></div>
<div data-bg="linear-gradient(to right, #E100FF, #7F00FF)"></div>
<script src="//code.jquery.com/jquery-3.1.0.js"></script>
You want to use jquery .addClass() function:
$('.myButton').addClass('myNewClass');
The function would probably look something like this:
$(function () {
$('.thumbnail').click(function() {
$('#box').addClass($(this).attr('id'));
});
})
You can get all the thumbnails as an array, and then iterate through the array and dynamically add an event listener to each, which will add the desired className to box when clicked:
var thumbnails = document.getElementsByClassName('thumbnail');
Array.from(thumbnails).forEach(function(thumbnail) {
var id = thumbnail.id;
thumbnail.addEventListener('click', function() {
document.getElementById('box').className = id.replace('btn', 'bg')
});
});

Categories

Resources