Clear style on every DOM element - javascript

I'm trying to find a smart way of clearing previously changed style property on every DOM element.
I know there is a way to clear styles like this
(margin is just an example attribute):
element_name.style.margin = "";
Clearing many elements with many styles attributes this way will take ages, so I hope there is some "all_at_once" solution.

This will clear the style of all tags:
const tags = document.querySelectorAll("*");
for (let i of tags) {
i.style = '';
}
<div style="background-color: beige">
<span style="color: red">Hello</span>
<p style="world">World</p>
</div>
You could also use i.removeAttribute('style'); to remove the style attribute.

You can get all the elements by using
document.querySelectorAll("*")
You will get an object with all the elements with numbered keys. Object.keys will give you an array of all the keys and with forEach you can iterate and apply the style or any manipulation to the elements.
var elem = document.querySelectorAll("*");
Object.keys(elem).forEach((e)=>elem[e].style.margin = "32px")
<div>scscs</div>
This can also be used
document.getElementsByTagName("*");
var elem = document.getElementsByTagName("*");
Object.keys(elem).forEach((e)=>elem[e].style.margin = "")
<div>scscs</div>
The document.getElementsByTagName("*"); shouldn't be used due to performance issues as mentioned by #ScottMarcus in comments

You have to remove inline styles and disable stylesheets:
function clearStyles() {
// remove inline styles:
document.querySelectorAll('*').forEach(e => e.style = null);
// disable stylesheets:
Object.values(document.styleSheets).forEach(v => v.disabled = true);
}
h1 {
color: pink
}
<h1 style="background:navy">My color was set in stylesheet<br>and background was set inline</h1>
<button onclick="clearStyles()">Clear styles</button>

.cssText
.cssText treats the whole value of .style as a string:
document.documentElement.querySelectorAll('*').forEach(tag => tag.style.cssText = '');
This expression will collect all tags within the <html> tag and overwrite all .style properties.
Demo
document.documentElement.querySelectorAll('*').forEach(tag => tag.style.cssText = '');
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>

Related

Can I clone, edit and append a div?

I'm trying to find out if it's possible to clone an HTML div with JS, edit it and append it again as a new element. So my source is, for example, this code here:
<div class="wrapper">
<div class="element">
<input id="test--1" value="ABC"/>
</div>
</div>
After copying this element, I need to find a way to change the attribute id of the new cloned input, clear the input value and paste it again in the wrapper so that it looks like this at the end:
<div class="wrapper">
<div class="element">
<input id="test--1" value="ABC"/>
</div>
<div class="element">
<input id="test--2" value=""/>
</div>
</div>
Does that make sense to you? If yes, how can I get this done? Or is it better to assign the content to a variable to append it? I'm looking for the best way here and maybe my idea is a solution too.
You can use pure JavaScript to do this by just cloning the .element div using the cloneNode() method, assign new id and value to the clone div and finally append it back to the document using the insertBefore() method like this:
let x = document.querySelector(".element");
let y = x.cloneNode(true);
y.children[0].id = "test--2";
y.children[0].defaultValue = "";
x.parentNode.insertBefore(y, x.nextSibling);
<div class="wrapper">
<div class="element">
<input id="test--1" value="ABC"/>
</div>
</div>
JSFiddle with the above code: https://jsfiddle.net/AndrewL64/jvc7reza/18/
Based on this answer you could do like:
$('#cloneBtn').on('click', function() {
// get the last input having ID starting with test--
var $inp = $('[id^="test--"]:last'); // Or use :first if you need
// Get parent element
var $div = $inp.closest('.element');
// Create clone
var $div_clone = $div.clone();
// Retrieve number from ID and increment it
var num = parseInt($inp.prop("id").match(/\d+/g), 10) + 1;
// Generate new number and assign to input
$div_clone.find('[id^="test--"]').prop({id: 'test--' + num, value: ''});
// Insert cloned element
$div.after($div_clone); // Or use .before() if you need
});
.element {
padding: 10px;
outline: 2px solid #0bf;
}
<button id="cloneBtn">CLICK TO CLONE</button>
<div class="wrapper">
<div class="element">
<input id="test--1" value="ABC" />
</div>
</div>
Once done inspect the input elements to see the new IDs
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
Scrambled elements, retrieve highest ID, increment, clone, append.
If your numbered IDs are scrambled, we first need a way to retrieve the highest ID number. Here's an implementation in pure JavaScript:
function cloneElement () {
const inpAll = document.querySelectorAll('[id^="test--"]');
if (!inpAll.length) return; // do nothing if no elements to clone
const maxID = Math.max.apply(Math, [...inpAll].map(el => +el.id.match(/\d+$/g)[0]));
const incID = maxID + 1;
const element = document.querySelector('.element'); // Get one for cloning
const eleClone = element.cloneNode(true);
const inpClone = eleClone.querySelector('[id^="test--"]');
inpClone.id = 'test--'+ incID;
inpClone.value = incID; // just for test. Use "" instead
document.querySelector('.wrapper').prepend(eleClone);
}
document.querySelector('#cloneBtn').addEventListener('click', cloneElement);
.element {
padding: 10px;
outline: 2px solid #0bf;
}
<button id="cloneBtn">CLICK TO CLONE</button>
<div class="wrapper">
<div class="element">
<input id="test--1" value="1" />
</div>
<div class="element">
<input id="test--23" value="23" />
</div>
<div class="element">
<input id="test--7" value="7" />
</div>
</div>
Once done inspect the input elements to see the new IDs
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
I don't know what data you know, why you want to do such a thing but it can be done :-)
One way is like that:
const elemToCopy = document.getElementById("test--1").parentNode; // I assume you know id
const copiedElem = elemToCopy.cloneNode(true);
const newInput = copiedElem.querySelector("#test--1");
newInput.id = "test--2";
newInput.value = "";
elemToCopy.parentNode.append(copiedElem);
Let me know in a comment if something is not clear :-)
Yes, use jQuery's .clone().
Here is an example that might be relevant to your situation:
let newElement = $('.element').clone();
newElement.find('input').attr('id', 'test--2').val('');
$('.wrapper').append(newElement);
Explanation
In the first line, we created a new cloned element by using jQuery clone().
Then, we found it's child input, changed it's ID and reset the val().
Finally, we found the .wrapper element and appended the new cloned element to it.

javascript flipping divs with the same class name horizontaly

I have a bunch of divs like this:
What I would like to do is flip the divs, so the first element becomes the last and the last element becomes first, essentially flipping divs around so 1element,2element,3element would become 3element, 2element, 1element.
I am not sure if this is even possible as there is nothing to distinguish those divs as they all have the same id and class name.
This question is similar to this one: Javascript only - sort a bunch of DIVs
except that here divs have the same id, class name so it makes it all harder.
You can first get all elements with your class, convert it into an array and call reverse() function that flips the array, then loop through the reversed array and append children back to your target div.
Sample codes
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div>
Original:
<div class="test">1</div>
<div class="test">2</div>
<div class="test">3</div>
<div class="test">4</div>
<div class="test">5</div>
</div>
<br />
<div id="target">
Reversed:
<!-- Will be created with Javascript -->
</div>
<script>
const reversedDivs = Array.from(document.getElementsByClassName("test")).reverse();
const targetDiv = document.getElementById("target");
// Create another list in reversed order
reversedDivs.forEach(div => {
const newDiv = div.cloneNode(true);
targetDiv.appendChild(newDiv);
})
</script>
</body>
</html>
Here's a working example: https://codesandbox.io/s/html-reverse-list-u3kld?fontsize=14&hidenavigation=1&theme=dark
...as there is nothing to distinguish those divs as they all have the same id and class name...
Ah, but there is! Where they are in their parent. You can get an array of the elements, reverse it, and then append them to the parent, which will move them so that they're in that reverse order:
var container = document.getElementById("container");
var divs = Array.from(container.children);
divs.reverse();
divs.forEach(function(div) {
container.appendChild(div);
});
Live Example:
setTimeout(function() {
var container = document.getElementById("container");
var divs = Array.from(container.children);
divs.reverse();
divs.forEach(function(div) {
container.appendChild(div);
});
}, 800);
.ib {
display: inline-block;
}
<div id="container"><div class="ib">1</div><div class="ib">2</div><div class="ib">3</div><div class="ib">4</div><div class="ib">5</div></div>
Note that I was careful to do the markup so that there wouldn't be any Text nodes in there, because the children collection only includes Elements, not Text nodes. But if you want to reverse all the children, including text nodes, use childNodes instead of children:
setTimeout(function() {
var container = document.getElementById("container");
var divs = Array.from(container.childNodes);
divs.reverse();
divs.forEach(function(div) {
container.appendChild(div);
});
}, 800);
.ib {
display: inline-block;
}
<div id="container">
<div class="ib">1</div>
<div class="ib">2</div>
<div class="ib">3</div>
<div class="ib">4</div>
<div class="ib">5</div>
</div>
Note that I've kept the code to ES5 level (not ES2015+), except that Array.from is more recent. You can easily polyfill it, or use
var divs = Array.prototype.slice.call(container.children/*or childNodes*/);
instead.

Style for loop with CSS

Im supposed to make 8 boxes and style them each, make the boxes with for loop. Every odd box should look different then the others. I have tried to make an id, but when i use the id in CSS, it wont do anything. Can someone help?
Here is the code i have:
var text = "";
var i;
for (i = 1; i < 10; i++) {
text += "Box number " + i + "<br>";
}
document.getElementById("demo").innerHTML = text;
.demo {
border: black;
}
<p id="demo"></p>
As volodymyr says use css nth-child property.
In javascript you can accomplish this in the following manner:
for(let i = 0; i < document.querySelectorAll('.class').length; i += 2){
document.querySelectorAll('.class')[i].style.color = 'red';
}
<div class="class">1</div>
<div class="class">2</div>
<div class="class">3</div>
<div class="class">4</div>
<div class="class">5</div>
<div class="class">6</div>
<div class="class">7</div>
<div class="class">8</div>
<div class="class">9</div>
<div class="class">10</div>
This uses a for loop which iterates over every odd element, and then applies styles via javascript. Usually a pure CSS implementation would be preferable though.
You can use css nth-clild property
.class:nth-child(odd) {background: red}
<div class="class">1</div>
<div class="class">2</div>
<div class="class">3</div>
<div class="class">4</div>
<div class="class">5</div>
<div class="class">6</div>
<div class="class">7</div>
<div class="class">8</div>
<div class="class">9</div>
<div class="class">10</div>
Your css references the "class" demo selector but your HTML uses an "id" property id='demo'. Change either one to match the other.

jQuery append method inserting text rather than HTML

I want append an input text in my html page. I use JQuery to do that.
My JQuery script :
$(document).ready(function(){
$(".reply").click(function(){
var tempat=$(this).parent().parent().next(".komentar-balasan");
console.log(tempat[0]);
var html=
tempat[0].append('<input type="text"></input>');
});
});
And the HTML :
<div class="isi">
<div class="like-comment">
<div class="kotak"></div>
<div class="kotak-jumlah">
</div>
<div class="kotak"><button class="reply"></button></div>
</div><div class="komentar-balasan"></div>
The Fiddle
I Don't know why, but instead of displayed the input text box. The browser just display <input type="text"></input>. It's like the browser didn't recognize the HTML code.
It's because tempat[0] is accessing the underlying DOM node rather than the jQuery wrapper. It works fine if you omit the array access and just call append on tempat.
You don't need it here but the right way to get a jQuery wrapped element of a jQuery selector list is to use eq
The problem is that you aren't calling the append element on a jQuery object (which treats strings as HTML), but instead on a native DOM element. The experimental ParentNode#append method treats strings as text, so you are seeing text.
If you omit the [0] before calling append, your code runs perfectly:
$(document).ready(function() {
$("#post-komentar").click(function() {
console.log($(this).siblings('.editor-komentar').val());
});
$(".reply").click(function() {
var tempat = $(this).parent().parent().next(".komentar-balasan");
console.log(tempat[0]);
var html =
tempat.append('<input type="text"></input>');
});
});
.reply {
background-color: #fff;
width: 20px;
height: 20px;
margin: 0;
padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="isi">
<div class="like-comment">
<div class="kotak"><</div>
<div class="kotak-jumlah">
</div>
<div class="kotak"><button class="reply"></button></div>
</div>
<div class="komentar-balasan"></div>
Hello,
Check if this is what you need:
You need to create an element and only then add it.
Here is an example:
$(document).ready(function(){
$(".reply").click(function(){
var tempat=$(this).parent().parent().next(".komentar-balasan");
console.log(tempat[0]);
var newEl = document.createElement('input');
newEl.type = "text";
tempat.append(newEl);
});
});
I hope I have helped!
Remove the [0]. You are dereferencing your jQuery object by doing that.
This works: tempat.append('<input type="text"></input>');

querySelectorAll root elements without using :scope

Let's assume we have this HTML structure:
<div id='test-div'>
<div class='random-class-1'>
<div class='useless-element-1'>
</div>
<div class='useless-element-2'>
</div>
<p>Just a paragraph, and useless</p>
</div>
<div class='random-class-2'>
<div class='useless-element-3'>
</div>
<div class='useless-element-4'>
</div>
<div class='useless-element-5'>
</div>
</div>
</div>
I need to select all children "DIV elements" (not grandchildren) inside the first DIV (in this example with id='test-div'), not from document but from element (div) itself.
So, I don't want to use the "query" below because I already have selected the element DIV [object HTMLDivElement]:
// I don't want to use this query
var children = document.querySelectorAll("div > div");
Just an example to achieve this (https://jsfiddle.net/t4gxt65k/):
// I already have selected DIV element
var el = document.getElementById("test-div")
// OR var el = document.querySelectorAll("#test-div");
var children = el.querySelectorAll(":scope > div");
But because of browser incompatibility I don't want to use ":scope"
The real question is:
How can I get the children (only DIV elements) of [object HTMLDivElement] using pure JavaScript?
As an option, you could set a temporary unique attribute for your scope element, and then use querySelectorAll() for its parent with the attribute selector prepended to what you would place after the :scope selector:
// The `scope` variable stores a reference to the scope element.
var attrName = '_scope' + Date.now();
scope.setAttribute(attrName, '');
var children = scope.parentNode.querySelector('[' + attrName + '] > DIV');
I’m not sure about how fast it is though.
Fwiw, specifically for getting child elements, there is the children DOM property:
var children = scope.children;
To get direct children of an element use a combination of parentNode.children or parentNode.childNodes, and Array.prototype.reduce like this:
var children = Array.prototype.reduce.call(el.children, function(acc, e) {
if(e.tagName == "DIV")
acc.push(e);
return acc;
}, []);
Similar to #Ibrahims answer in selecting children but less complicated since it does not address prototype and reduce. Instead it uses Array.from, Array.filter and Element.matches. Element.matches makes it more versatile since it uses a normal selector string (as you would in querySelectorAll).
Array.from(rootElement.children)
.filter(elm => elm.matches('div'))
const rootElement = document.getElementById('test-div')
Array.from(rootElement.children)
.filter(elm=>elm.matches('div'))
.forEach(elm=>elm.classList.add('matched'))
div {
padding: 1rem;
box-shadow: 0 0 0 1px gray inset;
}
.matched {
box-shadow: 0 0 0 1px red inset;
}
<div id='test-div'>
<div class='random-class-1'>
<div class='useless-element-1'></div>
<div class='useless-element-2'></div>
<p>Just a paragraph, and useless</p>
</div>
<div class='random-class-2'>
<div class='useless-element-3'></div>
<div class='useless-element-4'></div>
<div class='useless-element-5'></div>
</div>
</div>

Categories