How can i simplify this? (noob here) - javascript

i got this very long block and i think that it can be simplify but i dont know how to do it
const one = document.getElementById("one");
const two = document.getElementById("two");
const three = document.getElementById("three");
const four = document.getElementById("four");
one.onclick = () => {
one.innerHTML = "";
};
two.onclick = () => {
two.innerHTML = "";
};
three.onclick = () => {
three.innerHTML = "";
};
four.onclick = () => {
four.innerHTML = "";
};

I agree with Alex, using a class on the elements you wish to run the logic on makes more sense. For example:
const elements = document.querySelectorAll('.js-clear-on-click');
elements.forEach(el => el.addEventListener('click', event => {
el.textContent = '';
}));
Now you can reuse this functionality by just adding the class 'js-clear-on-click' on the DOM-element, so there will be no need to go back to your js-code and update it with 'five' for example.
Edit: If you wish to clear the element of all inner HTML, replace .textContent = ''; with .innerHTML = '';

You can create an array of id and use forEach on that and add event listeners dynamically
['one', 'two', 'three', 'four'].forEach(x => {
const element = document.getElementById(x);
element.onclick = function(){
element.innerHTML = '';
}
})

Or you can put 1 class for all elements, and use document.getElementsByClassName().
let eles = document.getElementsByClassName('yourClass');
for (let i = 0; i < eles.length; i++) {
eles[i].onclick = function () {
eles[i].innerHTML = '';
}
}

May be this way ?
['one','two','three','four']
.forEach(el=>document.getElementById(el)
.onclick=e=>e.target.textContent='');
proof:
['one','two','three','four']
.forEach(el=>document.getElementById(el)
.onclick=e=>e.target.textContent='');
div {
display: block;
width: 3em;
height:1.3em;
border: 1px solid grey;
margin: .7em 1em;
padding: .3em;
}
<div id="one" contenteditable >div 1</div>
<div id="two" contenteditable >div 2</div>
<div id="three" contenteditable >div 3</div>
<div id="four" contenteditable >div 4</div>
or if All elements have the same class (named "clearOnClick" here on snippet)
document.querySelectorAll('.clearOnClick')
.forEach(el=>el.onclick=e=>e.target.textContent='');
proof:
document.querySelectorAll('.clearOnClick')
.forEach(el=>el.onclick=e=>e.target.textContent='');
.clearOnClick {
display: block;
width: 3em;
height:1.3em;
border: 1px solid grey;
margin: .7em 1em;
padding: .3em;
}
<div id="one" contenteditable class="clearOnClick">div 1</div>
<div id="two" contenteditable class="clearOnClick">div 2</div>
<div id="three" contenteditable class="clearOnClick">div 3</div>
<div id="four" contenteditable class="clearOnClick">div 4</div>

Related

changing the content of a div

I would like to change the content of a div. I have three divs:
<div
class="box1"
style="height: 200px; width: 200px; background-color: red"
>
A
</div>
<br />
<div
class="box2"
style="height: 200px; width: 200px; background-color: blue"
>
<label for="">tex</label>
<input type="text" />
</div>
<br />
<div
class="box3"
style="height: 200px; width: 200px; background-color: yellow"
>
C
</div>
when the page is ready the 2 and 3rd box displays none:
function hideElementBoxOnLoad() {
let box1 = document.querySelector(".box1");
let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
box2.style.display = "none";
box3.style.display = "none";
}
$(document).ready(hideElementBoxOnLoad);
I want a click that toggles the content of box2 and box3 into box1 and then back to box1 content:
function changeContent() {
let chang = true;
let box1 = document.querySelector(".box1");
let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
let box2Content = box2.textContent;
let box3Content = box3.textContent;
if (chang) {
box1.textContent = box2Content;
chang = !chang;
if ((box1.textContent === box2Content)) {
box1.textContent = box3Content;
}
}
}
let btn = document.getElementById("btn");
btn.addEventListener("click", changeContent);
So far it worked but it does not display the content of box2 only box3. what did i do wrong and what better way can i toggle with a boolean.
See below
Instead of trying to swap content between each div just use JS to go through the array of them and swap an active class between them;
var boxes = document.getElementsByClassName('box');
var change = document.getElementById('change');
var counter = 0;
change.addEventListener('click', function(){
boxes[counter].classList.remove('active');
boxes[counter].nextElementSibling.classList.add('active');
counter++;
if(counter === boxes.length) {
counter = 0;
boxes[0].classList.add('active');
}
});
.box {
display: none;
width: 100px;
height: 100px;
background-color: gray;
}
.box.active {
display:block
}
<div class="box active">A</div>
<div class="box">B</div>
<div class="box">C</div>
<button id="change">Change Content</button>
im not completely sure if i understood ur question.
but below u can see and even test with the snippet button.
the button now add what ever content in in the yellow box, and whats in the input field of the blue box into the red box. listing them downwards.
if you want to replace the content completely.
just change the logic to box1.innerHTML += spacer+box3.innerHTML+spacer+input.value
this is the most simple way to do it thats easy to understand just by reading the code i think.
hope this helps!
function changeContent() {
//the button
const btn = document.getElementById("btn");
//the boxes
const box1 = document.getElementById("box1");
const box2 = document.getElementById("box2");
const box3 = document.getElementById("box3");
//a spacer
const spacer = "<br>";
//the input field
const input = document.getElementById("input");
//logic
box1.innerHTML += spacer+box3.innerHTML+spacer+input.value
}
div{
border-radius: 5px;
text-align: center;
font-family: sans-serif;
}
#box1{
min-height: 200px;
width: 200px;
padding: 5px;
background-color: rgb(255, 73, 73);
}
#box2 {
height: 200px;
width: 200px;
padding: 5px;
background-color: rgb(0, 195, 255);
}
#box3 {
height: 200px;
width: 200px;
padding: 5px;
background-color: yellow;
}
button{
padding: 3px;
margin-top: 10px;
}
<div id="box1">
<p>contetnt A</p>
</div>
<br />
<div id="box2" >
<label for="">tex</label>
<input id="input" type="text" />
<button id="btn" onclick="changeContent()">click me</button>
</div>
<br />
<div id="box3">
contetnt C
</div>
List of bugs :-
You had declared the var chang locally instead of globally, which make it true whenever you runs the function.
You are directly writing value from one tag to another, which causing the data loss, when you run your function second time.
For example :- When you click the button first time, the data is swapped, but for the second click, the data first div is lost and cannot be brought back...
Solution :- Store the data in an array in document.ready event handler and extract data from the array to update you html tags.
function hideElementBoxOnLoad() {
let box1 = document.querySelector(".box1");
let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
box2.style.display = "none";
box3.style.display = "none";
content = [box1.textContent, box2.textContent, box3.textContent];
let btn = document.getElementById("btn");
btn.addEventListener("click", changeContent);
}
var content = [];
window.onload = (hideElementBoxOnLoad);
var index = 0;
function changeContent() {
let chang = true;
let box1 = document.querySelector(".box1");
/* let box2 = document.querySelector(".box2");
let box3 = document.querySelector(".box3");
let box2Content = box2.textContent;
let box3Content = box3.textContent;
if (chang) {
box1.textContent = box2Content;
chang = !chang;
if ((box1.textContent === box2Content)) {
box1.textContent = box3Content;
}
}
*/
function cycle(n, x = 0, y = content.length - 1, a = 1) {
n += a;
if (n > y) return x;
if (n < x) return y;
return n;
}
index = cycle(index);
box1.textContent = content[index];
}
<div class="box1" style="height: 200px; width: 200px; background-color: red">
A
</div>
<br />
<div class="box2" style="height: 200px; width: 200px; background-color: blue">
<label for="">tex</label>
<input type="text" />
</div>
<br />
<div class="box3" style="height: 200px; width: 200px; background-color: yellow">
C
</div>
<button id="btn"> CLICK ME </button>
Explaination
Here I first stored the tags textContent in a array content, in the starting of the code.
Then, inside the button click handler, a simple cycle function to cycle on the values stored inside the content array.

How to save new background color via `colorpicker` to `localStorage`?

I know there's a lot of similar questions.. I've tried them but I really can't incorporate it to my project.
I'm trying to save to localStorage the new background-color selected using the native colorpicker.
I'm almost there but I just can't figure out how to make it work.
Please see my code so far:
function changeBgColor(color) {
if (color) window.localStorage.setItem('bgColor', color);
else if (!(color = window.localStorage.getItem('bgColor'))) return;
document.getElementById('colorpicker').addEventListener('input', function() {
var elements = document.getElementsByClassName("card-bg")
for (var i = 0; i < elements.length; i++) {
elements[i].style.background = this.value;
}
})
}
window.addEventListener('DOMContentLoaded', () => changeBgColor());
.card1 {
width: 200px;
height: 200px;
background-color: #222;
margin: 10px 0 0 0;
}
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<br>
<input type="color" id="colorpicker" onselect="changeBgColor();">
The important feature for me are:
To change background color using input="color"
Use class selector since I have multiple divs I want to target with the same input
Save the value to localStorage
That's all really. I just need to figure out the part where the value gets saved to localStorage.
After I make this work, I will need to replicate it for a different set of divs..
Thank you in advance for any help.
If check had = assignment instead of == comparison
Here is a working refactored snippet:
let pretend_local_storage = null
function setupBackgroundColorChange() {
const elements = document.querySelectorAll(".card-bg")
document.getElementById('colorpicker').addEventListener('input', function(e) {
color = e.target.value
if (color === pretend_local_storage) return
pretend_local_storage = color
elements.forEach((element) => element.style.background = color)
})
}
window.onDOMContentLoaded = setupBackgroundColorChange();
.card1 {
width: 200px;
height: 200px;
background-color: #222;
margin: 10px 0 0 0;
}
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<br>
<input type="color" id="colorpicker" onselect="changeBgColor();">
Local Storage example:
localStorage.getItem('bgColor', null)
function setupBackgroundColorChange() {
const elements = document.querySelectorAll(".card-bg")
setColor(elements, localStorage.getItem('bgColor', '#000'))
document.getElementById('colorpicker').addEventListener('input', function (e) {
color = e.target.value
if (color === localStorage.getItem('bgColor')) return
localStorage.setItem('bgColor', color)
setColor(elements, color)
})
}
function setColor(elements, color) {
elements.forEach((element) => element.style.background = color)
}
window.onDOMContentLoaded = setupBackgroundColorChange();
First of all i would use onchange trigger. To be honest, you dont need any condition inside the function. you can set the color to localStorage and that is it.
/* this lines check if already set color to localStorage */
if (window.localStorage.getItem('bgColor')) {
var elements = document.getElementsByClassName("card-bg")
for (var i = 0; i < elements.length; i++) {
elements[i].style.background = this.value;
}
}
function changeBgColor() {
let color = document.getElementById('colorpicker').value;
const bg_curr = localStorage.getItem('bgColor');
console.log(color, bg_curr);
localStorage.setItem('bgColor', color);
document.getElementById('colorpicker').addEventListener('input', function() {
var elements = document.getElementsByClassName("card-bg")
for (var i = 0; i < elements.length; i++) {
elements[i].style.background = color;
}
})
}
window.addEventListener('DOMContentLoaded', () => changeBgColor());
.card1 {
width: 200px;
height: 200px;
background-color: #222;
margin: 10px 0 0 0;
}
<input type="color" id="colorpicker" onchange="changeBgColor();">
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<br>

Move button when clicked

How do I move the button from the div with id of two to the div with id of one when I click the button?
<div id="one">
</div>
<div id="two">
<button onclick="moveMe"></button>
</div>
function moveMe() {
// ??
}
We can do this using removeChild and appendChild js features. Provided an example below with working code.
const one = document.getElementById("one");
const two = document.getElementById("two");
const allButtons = document.getElementsByTagName("button");
for(let i = 0; i < allButtons.length; i++) {
const btn = allButtons[i];
btn.addEventListener("click", function(e) {
const el = e.currentTarget;
const newParent = el.parentNode.id == "one" ? two : one;
el.parentNode.removeChild(el);
newParent.appendChild(el)
});
}
.section {
height: 100px;
width: 150px;
padding: 4px;
margin: 5px;
float: left;
}
#one {
background: #CCC;
}
#two {
background: #eee;
}
button {
margin: 2px;
padding: 4px;
}
<h3>Toggle button between container on click</h3>
<div>
<div class="section" id="one"></div>
<div class="section" id="two"> <button>Move me 1</button> <button>Move me 2</button></div>
</div>
function moveMe() {
const divTwo = document.getElementById("two")
const divOne = document.getElementById("one")
const newButton = document.createElement("button")
newButton.innerText = "Click me"
divOne.appendChild(newButton)
divTwo.children[1].remove()
}
<div id="one">
<p>
div one
</p>
</div>
<div id="two">
<p>
div two
</p>
<button onclick="moveMe()">Click me</button>
</div>
You can try this:
// select the elements
const button = document.querySelector('button');
const firstDiv = document.getElementById('one');
// add eventListener
button.addEventListener('click', moveButton);
// move the button
function moveButton() {
firstDiv.append(button);
}
<div id="one">
</div>
<div id="two">
<button id="btn" onclick="moveMe">MoveMe</button>
</div>
function moveMe() {
var divOne = document.querySelector("#one");
var btn = document.querySelector("#btn");
divOne.appendChild(btn);
}
You can use code below to move the element.
There's some changes that I made on your code,
you can use version 1 or version 2
the changes on first version is i add "id" attribute on the element so we don't resort to use the tag only as selector, of course you can also use #two>button to make it more precise
the changes on second version is i add a parameter to your function this time it will handle the current element using "this" keyword when calling the function
function moveMe(){
// one.appendChild(document.querySelector("button"));
one.appendChild(move);
}
function moveMeV2(element){
one.appendChild(element);
}
<div id="one">
<span>one</span>
</div>
<div id="two">
<span>two</span>
<button id="move" onclick="moveMe()">Move Me</button>
<button onclick="moveMeV2(this)">Move Me V2</button>
</div>

VanillaJS - find middle element in the container

So I have a setup like this
<div class=“container”>
<div class=“segment segment1”></div>
<div class=“segment segment2”></div>
<div class=“segment segment3”></div>
.
.
.
<div class=“segmentN”></div>
</div>
Where N is an number defined by user so list is dynamical. For container I have applied styles to display it as grid, so EVERY time list has 3 items displayed, list is scrollable. My problem is, how can I via VanillaJS find element which is in the middle of container ? If there are 3 elements in the page, it should select 2nd one, when scrolling down it should select element which is in the middle of container every time to apply some styles to it in addition to grab it’s id. If there are 2 elements, it should select 2nd item as well. I was thinking about checking height of container, divide it by half and checking position of element if it’s in range. So far I was able to write this code in js
function findMiddleSegment() {
//selecting container
const segmentListContainer = document.querySelector(`.container`);
const rect = segmentListContainer.getBoundingClientRect();
//selecting all divs
const segments = document.querySelectorAll(`.segment`);
segments.forEach( (segment) => {
const location = segment.getBoundingClientRect();
if( (location.top >= rect.height / 2) ){
segment.classList.add(`midsegment`);
} else {
segment.classList.remove(`midsegment`);
}
});
}
But it doesn’t work. It finds element in the middle as should, but also applies style for every other element beneath middle segment. I’ve read some answers on stackoverflow, but couldn’t find any idea how to solve my problem.
EDIT
In addition to my problem I add additional function to show how I invoke it.
function handleDOMChange() {
findMiddleSegment(); //for "first run" when doc is loaded
const segmentListContainer = document.querySelector(`.container`);
segmentListContainer.addEventListener('scroll', findMiddleSegment);
}
A very easy way to do it is using the Intersection Observer:
const list = document.querySelector('ul'),
idDisplay = document.querySelector('p b');
const observer = new IntersectionObserver(
highlightMid,
{
root: list,
rootMargin: "-33.33% 0%",
threshold: .5
}
);
function makeList() {
list.innerHTML = '';
observer.disconnect();
const N = document.querySelector('input').value;
for (let i = 0; i < N;) {
const item = document.createElement('li');
item.id = `i_${++i}`;
item.textContent = `Item #${i}`;
list.append(item);
observer.observe(item);
}
};
function highlightMid(entries) {
entries.forEach(entry => {
entry.target.classList
.toggle('active', entry.isIntersecting);
})
const active = list.querySelector('.active');
if (active) idDisplay.textContent = '#' + active.id;
}
ul {
width: 50vw;
height: 50vh;
margin: auto;
padding: 0;
overflow-y: auto;
border: solid 1px;
}
li {
box-sizing: border-box;
height: 33.33%;
padding: .3em 1em;
list-style: none;
transition: .3s;
}
.active {
background: #6af;
}
<i>Make a list of:</i>
<input type="number" min="2" placeholder="number of items">
<button onclick="makeList()">make</button>
<p>Active id is <b>yet to set</b></p>
<ul></ul>
If container has only a list of segments inside, it's easer to count the element's children and find the mid element.
const segmentListContainer = document.querySelector(`.segmentListContainer`);
const midSegmentIndex = Math.floor(segmentListContainer.children.length / 2) - 1;
let midSegment = segmentListContaner.children[midSegmentIndex];
midSegment.classList.add('midsegment');
P.S.
The reason why your code adds 'mdsegment' to each element's class name after the real midsegment element is because of this conditional statement line you wrote.
if(location.top >= rect.height / 2){
segment.classList.add(`midsegment`);
}
Something like this. You can use Math.round, Math.ceil or Math.floor like I did. This works because querySelectorAll returns an array and you can use array.length to count the total number of items in the array then use a for loop to loop over all the segments and place the class based on the Math.(round, floor or ceil) based on your needs.
const container = document.querySelector(".container");
const segments = container.querySelectorAll(".segment");
const middleSegment = Math.floor(segments.length / 2);
for (let index = 0; index < segments.length; index++) {
segments[middleSegment].classList.add("middle-segment");
}
.middle-segment{
background-color: red;
}
<div class="container">
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
</div>
You don't need javascript for this. CSS will do
.container {
width: 350px;
}
.container .segment {
width: 100px;
height: 100px;
float: left;
background-color: #EEE;
border: 1px dotted gray;
margin: 3px;
text-align: center;
color: silver;
}
.segment:nth-child(3n-1) {
background-color: aquamarine;
color: black;
}
<div class="container">
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
<div class="segment">segment</div>
</div>

Giving a div a style on click

applying a class to an element only when clicked
You could make 2 different click functions. One for trap and one for the rest.
For that you need to know which ones are the other ( safe ones ). See otherDivsIds in the below code. You find the other id's using the filter function in the idArray and then loop through them ( with forEach or something else ) and add event listeners to each of them.
I would also suggest to ' swap ' the naming of the variables trapBox and trapId. Vice versa would be better
See code below
var idArray = ['one','two','three','four'];
var trapBox = idArray[Math.floor(Math.random() * idArray.length)];
var trapId= document.getElementById(trapBox);
trapId.addEventListener('click', boomClickFunction, false);
var otherDivsIds = idArray.filter(id => id !== trapBox);
otherDivsIds.forEach(id => {
safeBox = document.getElementById(id);
safeBox.addEventListener('click', safeClickFunction, false)
})
var timeoutId = window.setTimeout(ticker, 5000);
function ticker() {
document.getElementById('timesUp').innerHTML = "Time's up!";
document.body.style.backgroundColor = "black";
}
function boomClickFunction() {
this.classList.add('boom')
}
function safeClickFunction() {
this.classList.add('safe')
}
div {
width: 20px;
height: 20px;
background-color: green;
margin: 20px;
float: left;
}
.boom {
background-color: red;
}
.safe {
background-color: lightblue;
}
#timesUp {
color: white;
}
<div id='one'>
</div>
<div id='two'>
</div>
<div id='three'>
</div>
<div id='four'>
</div>
<span id="timesUp">
</span>
You can add a class to an element by using classList.add('classToBeAdded').
In your case, you could put it in your clickFunction:
trapId.classList.add('boom');

Categories