Is it possible to call classes of nested divs with JS/Jquery? - javascript

I am unable to find this anywhere...Just wondering if it's possible to call nested divs and place them in one function? For example:
<div class="a">
<div class="b-1"></div>
<div class="b-2"></div>
</div>
How do I call them together as a function to update their styles?
Edit: I might not be too clear here. What I am trying to ask is... For example:
.a {
background-color: black; width:200px; height: 200px; position: relative; }
.b-1 { color: white;
position: absolute;}
.b-2 {color: white;
position: absolute; padding-top: 20px; }
<div class="a">
<div class="b-1"> test b1</div>
<div class="b-2"> test b2</div>
</div>
Is it possible to update a, b-1, b-2 classes in one function?
So the result is:
function updateMultipleClasses() {
change a to grey
change b1 and b2 to red
}
I would like to be able to just call this function instead. is this possible?

You can use jquery wild card selector
$("div[class^='b-']").addClass('test')
.test {
color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="a">
<div class="b-1">B-1</div>
<div class="b-2">B-2</div>
</div>

You can pass the NodeList by using querySelectorAll to your function that will select both parent and all children div elements and then use forEach loop on that selector.
function updateStyles(els) {
els.forEach(e => {
e.style.border = '1px solid red'
if (e.classList.contains('a')) {
e.style.backgroundColor = 'green'
}
if ([...e.classList].some(cls => ['b-1', 'b-2'].includes(cls))) {
e.style.backgroundColor = 'white'
}
})
}
updateStyles(document.querySelectorAll('.a, .a div'))
* {
padding: 5px
}
<div class="a">
<div class="b-1">1</div>
<div class="b-2">
<div class="b-3">3</div>
</div>
</div>

Don't use JS to style.
Use JS only to add a class to the .a Element, than use CSS to define the styles that should be applied to the ancestor and its children.
const makeSelected = (EL) => {
EL.classList.add("selected");
};
document.querySelectorAll(".a").forEach(makeSelected);
.a.selected {
color: gold;
}
.a.selected [class^="b-"],
.a.selected [class*=" b-"]{
color: fuchsia;
}
<div class="a">
a a a a a
<div class="b-1">b 1 1 1 1</div>
<div class="b-2">b 2 2 2 2</div>
</div>

Related

In Material UI what is the difference between a space after the ampersand and no space?

Can you please explain what is the difference between a space after the ampersand and no space
e.g.
Can you please explain why there is a space after the ampersand in & label.Mui-focused and no space in &.Mui-focused fieldset
const WhiteBorderTextField = styled(TextField)`
& label.Mui-focused {
color: white;
}
& .MuiOutlinedInput-root {
&.Mui-focused fieldset {
border-color: white;
}
}
`;
It's the same as CSS selectors:
<div class="a b">
a and b
</div>
<div class="c">
<div class="d">d inside c</div>
</div>
<div class="e">e</div>
<div class="f">f</div>
.a.b {
background-color: gold;
}
.c .d {
background-color: blue;
}
.e, .f {
background-color: red;
}
Here:
.a.b means an element which has class a AND b
.c .d means an element with class d WITHIN element with class .c
.e, .f means any element that has either e OR f as class
If you get confused how that turns into actual CSS use JSS playground:
This:
export default {
button: {
'& label.Mui-focused': {
color: 'white',
},
'& .MuiOutlinedInput-root': {
'&.Mui-focused fieldset': {
'border-color': 'white',
},
},
},
};
Will turn into:
.button-0-1-13 label.Mui-focused {
color: white;
}
.button-0-1-13 .MuiOutlinedInput-root.Mui-focused fieldset {
border-color: white;
}
^ Here the second selector targets a fieldset which appears WITHIN an element with MuiOutlinedInput-root AND Mui-focused class which is WITHIN a button. Something like:
<div class="button-0-1-13">
<div class="MuiOutlinedInput-root Mui-focused">
<fieldset>
Your fieldset here
</fieldset>
</div>
</div>

Why is classList.remove is not working but jQuery .removeClass is?

I'm still getting used to plain JavaScript and creating a basic set of square shaped divs that will add and remove classes when clicked. I'm using an array that will add a specific one of those classes. When clicking, I'd like to remove all of those classes before adding a new one. So for example, when clicking on the 2nd square, 'classB' will be added to only that one and then clicking any others will remove it.
I understand that classList.remove has to be before classList.add but for some reason it is not working. I always get the message "Cannot read property 'remove' of undefined at HTMLDivElement.elem.addEventListener".
However, if I use jQuery .removeClass it works with no problem. But I'd prefer not to use jQuery.
Here's the snippet. You can see the classList.remove that I was trying in what's commented out.
const addClass = ['classA','classB','classC','classD'];
const numbers = [0,1,2,3];
const square = document.querySelectorAll('.square');
square.forEach((elem, i) => {
elem.addEventListener('click', () => {
//square[i].classList.remove(...addClass)
$(square).removeClass('classA classB classC classD');
if (i == numbers[i]) {
elem.classList.add(addClass[i]);
}
});
});
.square {
width: 2rem;
height: 2rem;
background-color: black;
margin: 1rem;
}
.classA { background-color: red; }
.classB { background-color: yellow; }
.classC { background-color: green; }
.classD { background-color: blue; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>
I've looked through a bunch of other questions in here and on other sites but am not really seeing it.
The 2 methods you are comparing are not equivalent:
square[i].classList.remove(...addClass)
Will remove all of the classes in the array from one element.
$(square).removeClass('classA classB classC classD');
Will remove all of those classes from all the squares.
To do this without jQuery you could do:
square.forEach(elem => elem.classList.remove(...addClass));
const addClass = ['classA','classB','classC','classD'];
const numbers = [0,1,2,3];
const squares = document.querySelectorAll('.square');
// renamed square to squares so it's more obvious that it is a NodeList and not a single Node
squares.forEach((elem, i) => {
elem.addEventListener('click', () => {
squares.forEach(elem => elem.classList.remove(...addClass));
if (i == numbers[i]) {
elem.classList.add(addClass[i]);
}
});
});
.square {
width: 2rem;
height: 2rem;
background-color: black;
margin: 1rem;
}
.classA { background-color: red; }
.classB { background-color: yellow; }
.classC { background-color: green; }
.classD { background-color: blue; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>

Multiple DIVs with same class with each toggling independently between 2 DIVs

I have multiple divs with the same class (.item) and trying to figure out how to independently toggle between 2 divs (#open and #close).
For example, clicking on "A" or "B" toggles between "Open" and "Close" independently.
I've tried placing "(this)" before (.item), but it results in toggling not working at all.
$(this).on("click", function(event) {
$(event.target).closest(".item").toggleClass("highlight").toggleClass("marked unmarked");
if ($(".item").hasClass('unmarked')) {
$("#open").show();
$("#close").hide();
} else if ($(".item").hasClass('marked')) {
$("#close").show();
$("#open").hide();
} else {
$("#close").hide();
$("#open").hide();
}
});
.item {
text-align: center;
margin: 5px;
padding: 5px;
background: #EEEEEE;
}
.highlight {
background: orange;
}
#open,
#close {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="item marked">A</div>
<div class="item marked">B</div>
<div class="item marked">C</div>
<div id="open">Open</div>
<div id="close">Close</div>
Are you maybe looking for this behaviour?..
$('.item').on('click', function() {
if ($(this).hasClass('highlight')) {
$(this).removeClass('highlight');
$('#open').hide();
$('#close').show();
} else {
$('.item.highlight').removeClass('highlight');
$(this).addClass('highlight');
$('#open').show();
$('#close').hide();
}
})
.item {text-align: center;margin: 5px;padding: 5px;background: #EEEEEE;}
.highlight {background: orange;}
#open, #close {display: none;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div id="open">Open</div>
<div id="close">Close</div>
fiddle
https://jsfiddle.net/Hastig/127newyj/
Assuming I'm understanding your question correctly
My recommendation for this scenario is not to rely on the "this" keyword. $(this).on('click'.... is ridiculously broad. It needs to be contained in other code that would allow for a 'this' to be relative.
Instead, get your element by
var my_elemens = getElementsByClassName('item')
and refer to them by
my_elemens[0] // A
my_elemens[1] // B
my_elemens[2] // C
And then for whatever you're wanting to click, use it, so possibly...
$(myelemens[0]).on('click'....

jQuery | detach(), append() scope

I have a main-div and two divs with the class of container. The div with the class of container has a child div with a class of content with different contents. I'd like for the user to click on their choice of containers and transport its content to main-div. Then when the user clicks on the main-div, I'd like to transport that content back to its original div.
I'm not sure how to detach the content from main-div once it's been passed and reinsert it back into its original parent. I would appreciate any help.
I can't use IDs. I can only uses classes.
HTML
<div class="main-div">
</div>
<div class="container">
<div class="contents">
A
</div>
</div>
<div class="container">
<div class="contents">
B
</div>
</div>
CSS
.main-div {
width: 100wv;
height: 200px;
background: yellow;
cursor: pointer;
}
.container {
width: 40vw;
height: 150px;
border: 2px solid purple;
display: inline-block;
}
.contents {
width: 50px;
height: 50px;
background: green;
}
JS
$('.container').click(function() {
var child = $(this).children();
console.log('child ' + child);
$('.main-div').append(child);
});
$('.main-div').click(function(child) {
console.log('child ' + child);
$('.main-div').detach(child);
});
FIDDLE
Set ids for the containers
<div class="main-div">
</div>
<div class="container" id="container1">
<div class="contents">
A
</div>
</div>
<div class="container" id="container2">
<div class="contents">
B
</div>
</div>
And set a data attribute for the children on click to identify the parent element.
$(function() {
$('.container').click(function() {
var child = $(this).children();
child.attr("data-parentcontainer", this.id);
$('.main-div').append(child);
});
$('.main-div').click(function(child) {
var child = $(this).children();
child.appendTo($("#" + child.data("parentcontainer")));
});
});
JSFIDDLE
Use this JS snippet and let me know if it helps
$('.container').click(function() {
console.log('foo');
var child = $(this).html();
console.log(child);
$('.main-div').append(child);
});
$('.main-div').click(function() {
console.log('foo');
var main = $(this).html();
if(main.length != 0) {
$('.main-div').empty();
}
else
console.log('Main div is empty');
});
External DEMO
You can use .detach() and .appendTo(), but along with that you have to keep some identification to know from that .contents div was picked up. So I am making use of data-address attribute for the parent of picked .contents so as to attach it back there. See inline comments for detailed explanation on what will happen with the code.
$('.main-div').on('click', function(e) {
var elem = $(e.target); //capture click event on .main-div
if (elem.hasClass('contents')) { //check if click was on .contents div
var text = elem.text().trim(); //if yes then get its text
elem.detach();//detach the element
elem.appendTo($('div[data-address=' + text + ']')); //attach it based on attribute selector of jquery
}
});
$('.contents').on('click', function() {
var elem = $(this);//get the element
elem.closest('.container').attr('data-address', elem.text().trim())
//add or update data-address attribute of its closest parent i.e. .container
elem.detach();//detach the element
elem.appendTo($('.main-div')); //append it to .main-div
})
.main-div {
width: 200px;
height: 200px;
background: yellow;
cursor: pointer;
}
.container {
width: 150px;
height: 150px;
border: 2px solid purple;
}
.contents {
width: 50px;
height: 50px;
background: green;
position: relative;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main-div">
</div>
<div class="container">
<div class="contents">
A
</div>
</div>
<div class="container">
<div class="contents">
B
</div>
</div>
You need to add some uniqueness on the div that have class container, you can add a class or id so that when reinserting back to the original div we can identify the div.
i don't think is there other solution to reinsert back to the original div, whenever we identify both div uniquely.
please change your html structure so that we can manipulate through jquery.

Using jQuery to alternate between classes upon click event

I'm feeling awfully silly here - I can't get a simple class switching statement to work in jQuery! I can only sit in frustration as for the last 45 minutes, I've searched Stack Overflow questions and answers, to no avail.
My goal is, upon clicking an item with the colorClick id (already containing a default class of "white"), to rotate that item between being assigned the class green, yellow, orange, red, and back to white again (ad infinitum).
The CSS is simple - each class simply corresponds to a different background color.
The HTML is simple - a div tag with two CSS classes (one static, one to be changed by jQuery).
The jQuery is simple - read the class on the clicked item, and change it.
And now, you understand what vexes me. Here's what I'm working with so far:
$("#colorClick").click(function () {
if ($(this).hasClass('white')) {
$(this).removeClass("white").addClass("green");
} else if ($(this).hasClass('green')) {
$(this).removeClass('green').addClass('yellow');
} else if ($(this).hasClass('yellow')) {
$(this).removeClass('yellow').addClass('orange');
} else if ($(this).hasClass('orange')) {
$(this).removeClass('orange').addClass('red');
} else if ($(this).hasClass('red')) {
$(this).removeClass('red').addClass('white');
});
.toDoItem {
text-align: left;
padding: 3px;
margin-bottom: 5px;
border: 1px solid;
border-color: #e8e7e7;
}
.white {
background-color: #ffffff;
}
.green {
background-color: #b2d8b2;
}
.yellow {
background-color: #ffffb2;
}
.orange {
background-color: #ffe4b2;
}
.red {
background-color: #ffb2b2;
}
<div class="toDoItem white" id="colorClick">To-do list item</div>
<div class="toDoItem white" id="colorClick">To-do list item</div>
<div class="toDoItem white" id="colorClick">To-do list item</div>
Link to the fiddle:
http://jsfiddle.net/andrewcbailey89/4Lbm99v0/2/
First things first, when making a list, you should use the correct list elements. Your "To Do" list fits the definition of a description list (<dl>) so you should use that instead of <div> elements.
You can save a lot of lines of code by getting rid of the classes and creating an array of colors. Make sure that the colors are in the same order that you want them to be shown. We will use this array to set the background color based on an incremented counter.
var colors = ['#b2d8b2', '#ffffb2', '#ffe4b2', '#ffb2b2', '#fff'];
You can also greatly simplify your script by using a "factory" function which defines a scope and builds an event listener function, which it returns. This creates a "safe" scope for each listener function to reside in that we can define variables which will store information between events.
In the following snippet, we define a count variable that we increment on each click. We use the incremented variables remainder when dividing by the length of the color array using the modulo operator %. If the number is smaller than the length of the array, it will return the number, otherwise it will return the remainder when dividing by the length of the array, allowing us to loop through continuously.
function todoItemListener() {
var count = 0;
return function () {
$(this).css({ 'background-color': colors[count++ % colors.length] });
}
}
Then instead of assigning the function declaration as normal (without the parenthesis), we assign the result of the factory function, simply append the parenthesis and the function will execute and return the resulting listener function. This allows us to add as many listener functions as we want, so if you're adding new todo list items, we can simply build another listener function.
$('.todo-list dd').each(function () {
$(this).on('click', todoItemListener());
});
$('.add-item').on('click', function () {
var list = this.parentNode.parentNode;
$('<dd>To-do list item</dd>').appendTo(list).on('click', todoItemListener());
});
This method also allows you to easily change the array of colors at will. So say if an option is selected somewhere on the page, another color could become available, or not available.
Also, for some extra UX goodness, I added CSS to stop selection of the text on click (that can get annoying) and to change the cursor to a pointer to give it a more actionable feel.
Here is the full demo, I've included multiple to-do lists to show that it can be done.
var colors = ['#b2d8b2', '#ffffb2', '#ffe4b2', '#ffb2b2', '#fff'];
function todoItemListener() {
var count = 0;
return function () {
$(this).css({ 'background-color': colors[count++ % colors.length] });
}
}
$('.todo-list dd').each(function () {
$(this).on('click', todoItemListener());
});
$('.add-item').on('click', function () {
var list = this.parentNode.parentNode;
$('<dd>To-do list item</dd>').appendTo(list).on('click', todoItemListener());
});
.glyphicon-plus-sign {
font-size: 15px;
}
.todo-list {
background: #efefef;
padding: 3px;
}
.todo-list dd {
margin: 0;
text-align: left;
padding: 3px;
margin-bottom: 7px;
border: 1px solid;
border-color: #e8e7e7;
background-color: #fff;
}
.add-item, .todo-list dd {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
cursor: pointer;
}
.add-item {
float: right;
margin: 4px;
}
.todo-list dh::after {
content: "";
display: block;
clear: both;
}
.todo-list dh h3 {
float: left;
margin: 0px;
max-width: 100%;
overflow: hidden;
}
/* This rule is for the demo only */
.wrp {
float: left;
width: 33.33333333%;
padding: 1px;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div class="wrp">
<dl class="todo-list" id="todo-list-1">
<dh>
<h3 class="center" contenteditable>To Do List 1</h3>
<span class="add-item glyphicon glyphicon-plus-sign"></span>
</dh>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
</dl>
</div>
<div class="wrp">
<dl class="todo-list" id="todo-list-2">
<dh>
<h3 class="center">To Do List 2</h3>
<span class="add-item glyphicon glyphicon-plus-sign"></span>
</dh>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
</dl>
</div>
<div class="wrp">
<dl class="todo-list" id="todo-list-3">
<dh>
<h3 class="center">To Do List 3</h3>
<span class="add-item glyphicon glyphicon-plus-sign"></span>
</dh>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
</dl>
</div>
You are missing some quotes in a few places, and you didn't close the last if statement.
ex: $(this).hasClass(green) should be $(this).hasClass('green')
Additionally, you should change colorClick to a class rather than an ID, as there are multiple of these elements.
I also changed all of your quotes to single quotes for consistency's sake.
Here is a working snippet:
$(".colorClick").click(function () {
if ($(this).hasClass('white')) {
$(this).removeClass('white').addClass('green');
} else if ($(this).hasClass('green')) {
$(this).removeClass('green').addClass('yellow');
} else if ($(this).hasClass('yellow')) {
$(this).removeClass('yellow').addClass('orange');
} else if ($(this).hasClass('orange')) {
$(this).removeClass('orange').addClass('red');
} else if ($(this).hasClass('red')) {
$(this).removeClass('red').addClass('white');
}
});
.toDoItem {
text-align: left;
padding: 3px;
margin-bottom: 5px;
border: 1px solid;
border-color: #e8e7e7;
}
.white {
background-color: #ffffff;
}
.green {
background-color: #b2d8b2;
}
.yellow {
background-color: #ffffb2;
}
.orange {
background-color: #ffe4b2;
}
.red {
background-color: #ffb2b2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="colorClick toDoItem white">To-do list item</div>
<div class="colorClick toDoItem white">To-do list item</div>
<div class="colorClick toDoItem white">To-do list item</div>
First you are using same id for multiple elements. id should be unique for each element. You can use toDoItem class instead of colorClick id to bind click event. To get rid of complex if else statement you can put all class in an array in your required sequence. Then on click of toDoItem change class according to the sequence of array. If you reached at the last item of array then go back to first.
var colors = ['white', 'green', 'yellow', 'orange', 'red'];
var total = colors.length-1;
$(".toDoItem").click(function() {
var color = $(this).attr('class').split(' ')[1];
var index = colors.indexOf(color);
index = index==total? 0 : index+1;
$(this).removeClass(color).addClass(colors[index]);
});
.toDoItem {
text-align: left;
padding: 3px;
margin-bottom: 5px;
border: 1px solid;
border-color: #e8e7e7;
}
.white {
background-color: #ffffff;
}
.green {
background-color: #b2d8b2;
}
.yellow {
background-color: #ffffb2;
}
.orange {
background-color: #ffe4b2;
}
.red {
background-color: #ffb2b2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="toDoItem white">To-do list item</div>
<div class="toDoItem white">To-do list item</div>
<div class="toDoItem white">To-do list item</div>
JS FIDDLE DEMO

Categories

Resources