Creating a deep copy of a div - javascript

I'm trying to create a deep copy of a div. What I mean is that when the cloned copy of the div changes color, then the original div should change color as well.
What happens in the clone or in the original, should also happen in other one. Here's a JsFiddle
let clonedEle = $(".one").clone();
clonedEle.insertAfter(".one");
$(".one").click(function() {
$(this).css("background-color", "blue");
});
.one {
background-color: red;
width: 50px;
height: 50px;
margin-bottom: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="one">
</div>
My goal is to get both divs blue when we click either one. In this example, only one of the divs becomes blue when you click on them instead of both at the same time. How do I achieve this?

This is just a sample of how you could solve this using a customized built-in element:
class MyDiv extends HTMLDivElement {
connectedCallback() {
this.addEventListener('click', () => {
this.setAttribute('style', 'background-color: #999');
})
}
static get observedAttributes() { return ['style'] }
attributeChangedCallback(attr, oldVal, newVal) {
switch (attr) {
case 'style':
if (oldVal === newVal) break; // avoid infinite loops
const myDivs = document.querySelectorAll('[is="my-div"]');
for (const div of myDivs) { div.setAttribute('style', newVal) };
break;
}
}
}
customElements.define('my-div', MyDiv, { extends: 'div' });
cloneBtn.addEventListener('click', (e) => {
let theDiv = e.target.nextElementSibling.cloneNode(true);
document.body.appendChild(theDiv);
})
<button type="button" id="cloneBtn">Clone the div</button>
<div is="my-div">my div</div>
Try changing the style attribute of any of the my-divelements in the developer tools of your browser. You'll see that any inline style you give to my-div is automatically applied to any other my-div on the document as well.

$(this) points to only current element and here you wanted to apply color on both the div with same class. So, use $(".one")
Try this -
let clonedEle = $(".one").clone();
clonedEle.insertAfter(".one");
$(".one").click(function() {
$(".one").css("background-color", "blue");
});
Hope this will help you.

Related

How to toggle between two background images for a div having an event listener

It's a to do list and here's the JS I'm stuck into -
function taskCheck() {
let taskCheckboxImg = this.style.backgroundImage;
if(taskCheckboxImg=="url('img/uncheck.png')") {
taskCheckboxImg="url('img/check.png')";
} else {
taskCheckboxImg="url('img/uncheck.png')";
}
}
I want to toggle between check and uncheck by changing the background image when clicked but the if statement doesn't seem to work. Perhaps it doesn't change the background image property in the 4th line.
I could have done this with a regular checkbox but it doesn't seem to have editable properties in CSS. Help!
You are assigning the value to a variable, instead you need to change the value of the CSS property after each condition like
this.style.backgroundImage = "url('img/check.png')";
Also, you are using this, which refers to the current object, so make sure you have the this context available from wherever you call taskCheck() function
You function after the change should look like below
function taskCheck() {
let taskCheckboxImg = this.style.backgroundImage;
if(taskCheckboxImg=="url('img/uncheck.png')") {
this.style.backgroundImage="url('img/check.png')";
} else {
this.style.backgroundImage="url('img/uncheck.png')";
}
}
const myDiv = document.querySelector('div')
myDiv.addEventListener('click', taskCheck)
function taskCheck(e) {
let taskCheckboxImg = e.target.style.backgroundImage;
if(taskCheckboxImg=='url("https://picsum.photos/id/200/200/200")') {
// you have to change css property like this
e.target.style.backgroundImage='url("https://picsum.photos/id/300/200/200")';
} else {
console.log(taskCheckboxImg)
e.target.style.backgroundImage='url("https://picsum.photos/id/200/200/200")';
}
}
div{
width: 200px;
height: 200px;
background-size: cover;
}
<div style="background-image:url('https://picsum.photos/id/200/200/200')"></div>

How to add class to a div that has adjacent sibling using javascript or react?

i want to add a class to a div that has adjacent sibling selector.
Below is the html code,
<div class="wrapper">
<div class="prev_div">previous</div>
<div class="next_div">next</div>
</div>
I want to add margin property to the div with class "prev_div". I tried doing that with css as below,
.wrapper div.prev_div + div.next_div {
margin: 10px;
}
But the above adds the margin to the div with class next_div instead i wanted the margin style for the prev_div.
So i tried doing the same using the javascript by finding the element with prev_div and next_div. if next_div present adding a class "additional" to the prev_div. once class additional added and if the next_div not present remove the additional class for prev_div. but this doesnt work...there is a delay in removing the class added when next_div not present.
render = () => {
const prev_div = document.querySelector('wrapper div.prev_div');
const next_div = document.querySelector('wrapper div.prev_div + div.next_div');
if (next_div) {
prev_div.classList.add('additional');
} else {
if (prev_div && prev_div.classList.contains('additional')) {
prev_div.classList.remove('additional');
}
}
}
Could someone help me fix this or provide a better solution to do this. thanks.
Actually your js code is working, just missed dot . before wrapper
const prev_div = document.querySelector(".wrapper div.prev_div");
const next_div = document.querySelector(
".wrapper div.prev_div + div.next_div"
);
console.log("prev_div", prev_div);
console.log("next_div", next_div);
if (next_div) {
prev_div.classList.add("additional");
} else {
if (prev_div && prev_div.classList.contains("additional")) {
prev_div.classList.remove("additional");
}
}
.additional {
margin: 10px;
}
<div class="wrapper">
<div class="prev_div">previous</div>
<div class="next_div">next</div>
</div>
Also there is more beautiful solution to add a class to element that has next sibling
const elem = document.querySelector(".prev_div");
const isNexSibling = elem => {
const nextSibling = elem.nextElementSibling;
if (nextSibling) {
elem.classList.add("additional");
}
};
isNexSibling(elem);

How can I pass only the styles of an element to another element?

I was trying to pass the CSS of a element to another element, I wrote a function (demo included):
extendcss = (el1, el2) => {
if(typeof(el1) == 'object' && typeof(el2) == 'object'){
Array.prototype.slice.call(el1.attributes).forEach(function (item) {
el2.setAttribute(item.name, item.value);
});
}
else{
Array.prototype.slice.call(document.querySelector(el1).attributes).forEach(function (item) {
document.querySelector(el2).setAttribute(item.name, item.value);
});
}
}
$('button').click(()=>{
extendcss('#parent', '#child');
});
#parent{
color: white;
background: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id="parent">Parent</h1>
<h1 id="child">Child</h1>
<button>DO</button>
The problem is that, when the method is called, all the attributes of the first element, like id, class, style, and other things get included and added to second element. I haven't figured out how to pass the style only to the second element.
Please help me in passing only style of the element from the element.

How can you re-render a page from JavaScript/jQuery?

I am not quite sure if that's the correct way to phrase it, but here is my problem
As you can see, pretty simple code:
<div class="first"></div>
<div></div>
What I want to achieve is:
You click on the div with the first class, it will swap that class with the sibling element
You click the sibling element, and it swaps it back, so you just swap classes around 2 elements
The problem here is it works correctly only the first time, and the second time when the new element receives the class via addClass, jQuery doesn't recognize that it contains the class by the first page load? How can I resolve this?
P.S: I made a console.log(111); just to make sure, and sure enough it triggers ONLY when I click on the black div after the first swap (the one that SHOULD NOT have the first class anymore)
To achieve this behavior, you can use delegated events http://api.jquery.com/delegate/ on elements wrapper;
$(document).delegate('.first', 'click', function(e){
e.preventDefault();
console.log(123);
$(this).removeClass('first');
$(this).siblings().addClass('first');
})
A quick and simple way to do it is this:
$(document).ready(function() {
var first = $('.first');
var second = first.next();
first.click(function(e) {
e.preventDefault();
first.removeClass('first');
second.addClass('first');
});
second.click(function(e) {
e.preventDefault();
second.removeClass('first');
first.addClass('first');
});
});
div {
background-color: black;
height: 100px;
width: 100px;
margin-bottom: 10px;
}
.first {
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="first"></div>
<div></div>
This way does not scale well.
Your problem was you only change when you click the $(first) which does not change when clicked it's still point to the first div.
A better way with vanilla javascript:
document.addEventListener('click', function(e) {
if (e.target.classList.contains('first')) {
e.target.classList.remove('first')
var sibling = getNextSibling(e.target) || getPreviousSibling(e.target)
if (sibling) {
sibling.classList.add('first')
}
}
})
function getNextSibling(elem) {
var sibling = elem.nextSibling
while(sibling && sibling.nodeType != 1) {
sibling = sibling.nextSibling
}
return sibling
}
function getPreviousSibling(elem) {
var sibling = elem.previousSibling
while(sibling && sibling.nodeType != 1) {
sibling = sibling.previousSibling
}
return sibling
}
All you need to do is push both items into an array, then flip between indexes on click.
var elems = [];
$(document).on("click", ".first", function(event) {
elems = elems.length == 0 ? [event.originalEvent.target, $(event.originalEvent.target).next()] : elems;
$(elems[event.originalEvent.target === elems[0] ? 1 : 0]).addClass("first");
$(elems[event.originalEvent.target === elems[0] ? 0 : 1]).removeClass("first");
});
.first {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="first">x</div>
<div>y</div>

Toggle class to an element by click another element

I want to click on an element to toggle a class being referenced on a completely unrelated element (not a child, parent or sibling)
For example, initially the code would look like this
<a id="button">Button</a>
<div class="navigation">
Foo
</div>
When the user clicks the element with the id button the HTML would change to look like this (the class "open" is referenced on element with "navigation" already referenced":
<a id="button">Button</a>
<div class="navigation open">
Foo
</div>
The user should be able to toggle the class by clicking the element with the id button.
I would like to use pure javascript to achieve this effect.
You could attach click event to the button with id button then on click select the element with class navigation using getElementsByClassName() (ti will return list of nodes) then select the first one using [0] then use toggle() :
document.getElementById('button').onclick = function(){
document.getElementsByClassName('navigation')[0].classList.toggle("open");
}
Hope this helps.
document.getElementById('button').onclick = function(){
document.getElementsByClassName('navigation')[0].classList.toggle("open");
}
.open{
background-color: green;
color: white;
}
<a id="button">Button</a>
<div class="navigation">
Foo
</div>
You don't really need javascript. Checkboxes work great at storing on/off state. You just need to get a little crafty with the CSS to use it elsewhere. Here is an example:
label.divcheck { color:blue; text-decoration:underline; }
input.divcheck { display:none; }
input.divcheck + div { display:none; }
input.divcheck:checked + div { display:block;}
<label class="divcheck" for="navigation">Button Nav</label>
<label class="divcheck" for="other">Button Other</label>
<input type="checkbox" class="divcheck" id="navigation"/>
<div class="navigation">
Foo
</div>
<input type="checkbox" class="divcheck" id="other"/>
<div class="navigation">
Other
</div>
Multiple elements with class navigation
navigation is a class, so I assume there is more than one element you would like to give class open on click on element with id button. Do it that way:
function toggleNavigation(element) {
element.classList.toggle('open');
}
document.getElementById('button').addEventListener('click', function() {
Array.from(document.getElementsByClassName('navigation')).forEach(toggleNavigation);
});
.navigation {
background-color: lightgreen;
}
.navigation.open {
background-color: lightblue;
}
<a id="button">Button</a>
<div class="navigation">Foo</div>
<div class="navigation">Foo</div>
<div class="navigation">Foo</div>
Single element with class or id navigation
If it is otherwise (i.e., there is only one element with class navigation, in which case it should be an id, not a class) you can replace above JavaScript to:
document.getElementById('button').addEventListener('click', function() {
document.getElementsByClassName('navigation')[0].classList.toggle('open');
});
or if you will change navigation to be an id:
document.getElementById('button').addEventListener('click', function() {
document.getElementById('navigation').classList.toggle('open');
});
You need to add event handlers. This can be done by simple setting the onClick property on the Element object:
document.getElementById('button').onClick = function onClick() {
document.getElementsByClassName('navigation')[0].className += 'open';
};
However, it's preferable that you use addEventListener so multiple event listeners can be added to the same element:
document.getElementById('button').addEventListener('click', function onClick() {
document.getElementsByClassName('navigation')[0].className += 'open';
}, false);
EDIT: It's also better to cache your element references in variables like so:
var button = document.getElementById('button');
var nav = document.getElementsByClassName('navigation')[0];
button.addEventListener('click', function onClick() {
nav.className += 'open';
}, false);
EDIT2: as in Zakaria's answer, you may want to use classList.add(x) instead of className += x. It's more in line with how jQuery's things work. However, be aware that classList is not supported in older versions of IE.
EDIT3: Here's a final version using classList.toggle
var button = document.getElementById('button');
var nav = document.getElementsByClassName('navigation')[0];
button.addEventListener('click', function onClick() {
nav.classList.toggle('open');
}, false);
And here's a quick replacement for classList using className instead:
function classList(elem) {
var cl = {
add: function (clas) {
elem.className += clas;
},
remove: function (clas) {
elem.className = elem.className.replace(clas, '');
},
toggle: function (clas) {
if (elem.className.indexOf(clas) > -1) {
cl.remove(clas);
} else {
cl.add(clas);
}
}
};
return cl;
}
// usage
classList(nav).add('open');
classList(nav).toggle('open');
Try this:
document.querySelector('div.navigation').classList.toggle('open');
This will work if you only have one div element that has the class navigation. It would be better to give it an id, for example id=navigation

Categories