I created this JavaScript code which detects the value (number) of select tags and creates div contents based on that value and appends them into the container, but when I change the value again it keeps going, it doesn't reset.
The code is the following:
const select = document.getElementsByTagName('select')[0];
const container = document.getElementById('container');
select.onchange = () => {
for (let i = 0; i < Number(select.value); i++) {
let content = document.createElement('div');
content.classList.add('content');
container.appendChild(content);
}
}
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
height: 100vh;
}
.app {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 12% 88%;
background: #5F9EA0;
}
select {
width: 60px;
height: 40px;
background: red;
color: #fff;
font-size: 24px;
border-radius: 10px;
outline: none;
}
#container {
width: 100%;
height: 100%;
background: darkcyan;
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.content {
width: 150px;
height: 150px;
border-radius: 15px;
background: darkgreen;
margin: 10px;
}
<div class="app">
<select>
<option>0</option>
<option>3</option>
<option>6</option>
<option>9</option>
</select>
<div id="container"></div>
</div>
How can I reset the contents before adding the other contents?
you see on change iam removing everything inside container then goes your logic
const select = document.getElementsByTagName('select')[0];
const container = document.getElementById('container');
select.onchange = () => {
container.innerHTML = "";
for (let i = 0; i < Number(select.value); i++) {
let content = document.createElement('div');
content.classList.add('content'); container.appendChild(content);
}
}
You can reset container by setting its innerHTML to empty string.
const select = document.getElementsByTagName('select')[0];
const container = document.getElementById('container');
select.onchange = () => {
// reset
container.innerHTML = "";
for (let i = 0; i < Number(select.value); i++) {
let content = document.createElement('div');
content.classList.add('content');
container.appendChild(content);
}
}
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
height: 100vh;
}
.app {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 12% 88%;
background: #5F9EA0;
}
select {
width: 60px;
height: 40px;
background: red;
color: #fff;
font-size: 24px;
border-radius: 10px;
outline: none;
}
#container {
width: 100%;
height: 100%;
background: darkcyan;
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.content {
width: 150px;
height: 150px;
border-radius: 15px;
background: darkgreen;
margin: 10px;
}
<div class="app">
<select>
<option>0</option>
<option>3</option>
<option>6</option>
<option>9</option>
</select>
<div id="container"></div>
</div>
You could do something like this:
check if the current select.value is less or equal the original squares if true, you remove all of them and then add the new squares according to the number selected
const addSquares = select => {
for (let i = 0; i < Number(select.value); i++) {
let content = document.createElement("div")
content.classList.add("content")
container.appendChild(content)
}
}
const select = document.getElementsByTagName("select")[0]
const container = document.getElementById("container")
select.onchange = () => {
const squares = document.querySelectorAll(".content")
const squareArr = Array.from(squares)
const { value } = select
if (value <= squareArr.length) {
squareArr.forEach(function (node) {
node.parentNode.removeChild(node)
})
}
addSquares(select)
}
I think this is the most convenient way.
Each time you click the button, you need to clear the previous time
const select = document.getElementsByTagName('select')[0];
const container = document.getElementById('container');
select.onchange = () => {
container.innerHTML = '';
for (let i = 0; i < Number(select.value); i++) {
let content = document.createElement('div');
content.classList.add('content');
container.appendChild(content);
}
}
Related
I saved all dom-elements in an object. I want that my Script is able to check every time when there is some input if all input fields are empty anymore. If yes, the button should still be disabled, otherwise the forward button is enabled and the user can click to the next page.
Ways like like using querySelectorAll input field etc. are working but I want that this is working with using the object.
The "areTruthy" variable is directly true if one input field is not empty anymore but it should only be true if all input fields are true. Where is my code wrong?
window.onload = () => {
forward = document.getElementById("forward");
input = {
caseNumber: {
month: document.getElementById("month"),
year: document.getElementById("year"),
},
clientsInformation: {
gender: document.getElementById("gender"),
inpName: document.getElementById("inpName"),
},
adress: {
street: document.getElementById("street"),
houseNumber: document.getElementById("house-number"),
postCode: document.getElementById("postCode"),
city: document.getElementById("city"),
receiver: document.getElementById("receiver"),
},
};
addEventListener("input", () => {
for (parts in input) {
const areTruthy = Object.values(input[parts]).every((value) => value != "");
if (areTruthy) {
forward.style.backgroundColor = "rgb(77,55,120)";
forward.style.color = "white";
forward.disabled = false;
forward.style.transition = "1s ease";
forward.addEventListener("click", () => {
window.open("case.html");
});
} else {
forward.style.backgroundColor = "rgb(191,191,191)";
forward.style.color = "black";
forward.disabled = true;
}
}
});
};
<body>
<h3>Fill in all fields</h3>
<div id = "wrapper">
<div id = "caseNumber">
<label id = "caseLabel"></label>
<input id = "month" placeholder="Zahlenfolge">
<input id = "year" placeholder = "Jahr">
</div>
<div id = "name">
<label for = "name">Name</label>
<select id = "gender">
<option>Herr</option>
<option>Frau</option>
</select>
<input id = "inpName" placeholder = "Name">
</div>
<div id = "adress">
<label for = "adress">Adresse</label>
<div id = "adressWrapper1">
<input placeholder = "Straße" id = "street" >
<input placeholder = "Hausnummer" id = "house-number">
<input placeholder = "Postleitzahl" id = "postCode" >
</div>
<div id = "adressWrapper2">
<input placeholder = "Stadt" id = "city" >
<input placeholder = "Adressant" id = "receiver" >
</div>
</div>
</div>
</div>
<div class = "button-bar">
<div class = "nav-inner" id = "backward"><a class = "nav-inner" href= "#http://127.0.0.1:5500/pages/client.html" ></a> < Zurück</div>
<div class = "nav-inner" id = "forward"> Weiter ></div>
</div>
</body>
</html>
.navbar {
display: flex;
list-style: none;
background-color: rgb(77, 55, 120);
margin: 0;
position: fixed;
width: 100%;
gap: 4rem;
height: 50px;
text-align: center;
line-height: 45px;
left: 0;
top: 0;
}
.nav-text {
text-decoration: none;
color: white;
width: auto;
cursor: pointer;
font-size: 18px;
padding-bottom: 5px;
}
#wrapper {
margin-top: 10rem;
margin-left: 5rem;
display: sticky;
}
#caseNumber {
display: block;
}
input::placeholder {
font-size: 1rem;
text-align: center;
line-height: 19rem;
}
.button-bar {
position: fixed;
bottom: 0;
width: 100%;
display: flex;
margin: 0;
left: 0;
}
.nav-inner {
cursor: pointer;
width: 50%;
text-align: center;
line-height: 83px;
}
#backward {
background-color: rgb(101, 93, 93);
color: white;
}
#forward {
background-color: rgb(191, 191, 191);
}
h3 {
left: 20vh;
position: absolute;
font-size: 24px;
margin-top: 0.5rem;
}
#caseNumber {
position: absolute;
left: 20vh;
margin-top: 6.5rem;
text-align: left;
}
#name {
position: absolute;
left: 20vh;
margin-top: 12.5rem;
}
label {
display: inline-block;
text-align: left;
width: 140px;
font-size: 20px;
}
input,
select {
width: 30vh;
height: 5vh;
font-size: 19px;
border-radius: 5px;
border-style: solid;
border: 1px solid;
}
#adress {
position: absolute;
left: 20vh;
margin-top: 18.5rem;
max-width: 40rem;
display: block;
}
#adressWrapper1 {
display: flex;
gap:5vh;
flex-direction: column;
left: 18vh;
position: absolute;
top:0rem
}
#adressWrapper2 {
display: flex;
gap:5vh;
flex-direction: column;
position: absolute;
left: 50vh;
top:0rem
}
You are not checking input values. Also you are only checking every on child per parent object key, not on all children together so you need to lift if outside for
addEventListener("input", () => {
let allFilled = true;
for (parts in input) {
const anyEmpty = Object.values(input[parts]).some(el => el.value == "");
if (anyEmpty) {
allFilled = false;
break;
}
}
if (allFilled) {
forward.style.backgroundColor = "rgb(77,55,120)";
forward.style.color = "white";
forward.disabled = false;
forward.style.transition = "1s ease";
forward.addEventListener("click", () => {
window.open("case.html");
});
} else {
forward.style.backgroundColor = "rgb(191,191,191)";
forward.style.color = "black";
forward.disabled = true;
}
});
};
If you want to see what is exactly happening you can use this to log
const anyEmpty = Object.values(input[parts]).some((el) => {
console.log(el, el.value, el.value == "");
return el.value == "";
});
I wanted to remove an element created using the JavaScript of specific class when clicked outside the box .
I have used created a color-picker using .createElement . Add a class to it .
Now I wanted to remove that picker when outside of its parent element is clicked as sometimes users don't pick the color and on every click a color-picker is created .
How my function works :
Click on circle option will open up to change : borderColor or backgroundColor
When one option is chosen the color of that property is changed
var restyleBG = document.getElementsByClassName("restyleBackground");
restyleBG[0].addEventListener('click', changeBGcolor);
function changeBGcolor() {
let optionChooseBackground = document.getElementById("optionToChooseBackground");
optionChooseBackground.style.display = "block";
let optionChooseTag = optionChooseBackground.getElementsByTagName("p")
for (let j = 0; j < optionChooseTag.length; j++) {
optionChooseTag[j].onclick = function() {
var varWantToChange = optionChooseTag[j].innerHTML;
let optionToChoosePicker = document.getElementById("optionToChoose");
let colourPicker = document.createElement("input");
colourPicker.type = "color";
colourPicker.className = "colour-picker";
optionToChoosePicker.appendChild(colourPicker);
colourPicker.click();
colourPicker.addEventListener('input', function() {
var colorPickerVal = colourPicker.value;
if (varWantToChange == "borderColor") {
restyleBG[0].style.borderColor = colorPickerVal;
} else if (varWantToChange == "backgroundColor") {
restyleBG[0].style.backgroundColor = colorPickerVal;
}
})
}
}
}
#optionToChoose {
border: 2px solid red;
width: 200px;
}
#optionToChooseBackground {
position: absolute;
height: 100vh;
width: 100vw;
background-color: rgba(165, 42, 42, 0.205);
display: none;
}
#clockOuterCircle {
display: flex;
justify-content: center;
align-items: center;
width: 42vw;
height: 42vw;
margin: auto;
border-radius: 50%;
border: 4px solid rgb(255, 62, 62);
background-color: rgb(253, 133, 133);
user-select: none;
}
<div id="optionToChooseBackground">
<div id="optionToChoose">
<h3>Choose a style want to change :</h3>
<h4>Border</h4>
<p>borderColor</p>
<p>backgroundColor</p>
</div>
</div>
<div id="clockOuterCircle" class="restyleBackground"></div>
Upto now works as needed but creating pickers on each click whether choosing a color or not (not used a on-change event on color picker which executes when color value is changed and remove the picker but this don't come in handy when user just click the property and don't change the color).
The method I tried is in below snippet that when outside of color-picker parent element is clicked it removes the created element but this is throwing error when clicked .
var restyleBG = document.getElementsByClassName("restyleBackground");
restyleBG[0].addEventListener('click', changeBGcolor);
function changeBGcolor() {
let optionChooseBackground = document.getElementById("optionToChooseBackground");
optionChooseBackground.style.display = "block";
let optionChooseTag = optionChooseBackground.getElementsByTagName("p")
for (let j = 0; j < optionChooseTag.length; j++) {
optionChooseTag[j].onclick = function() {
var varWantToChange = optionChooseTag[j].innerHTML;
let optionToChoosePicker = document.getElementById("optionToChoose");
let colourPicker = document.createElement("input");
colourPicker.type = "color";
colourPicker.className = "colour-picker";
optionToChoosePicker.appendChild(colourPicker);
colourPicker.click();
colourPicker.addEventListener('input', function() {
var colorPickerVal = colourPicker.value;
if (varWantToChange == "borderColor") {
restyleBG[0].style.borderColor = colorPickerVal;
} else if (varWantToChange == "backgroundColor") {
restyleBG[0].style.backgroundColor = colorPickerVal;
}
})
optionChooseBackground.addEventListener('click', optionChooseBackgroundClose)
function optionChooseBackgroundClose() {
if (event.target == optionChooseBackground) {
let optionToChoosePicker = document.getElementById("optionToChoose");
optionToChoosePicker.removeChild(colourPicker);
}
}
}
}
}
#optionToChoose {
border: 2px solid red;
width: 200px;
}
#optionToChooseBackground {
position: absolute;
height: 100vh;
width: 100vw;
background-color: rgba(165, 42, 42, 0.205);
display: none;
}
#clockOuterCircle {
display: flex;
justify-content: center;
align-items: center;
width: 42vw;
height: 42vw;
margin: auto;
border-radius: 50%;
border: 4px solid rgb(255, 62, 62);
background-color: rgb(253, 133, 133);
user-select: none;
}
<div id="optionToChooseBackground">
<div id="optionToChoose">
<h3>Choose a style want to change :</h3>
<h4>Border</h4>
<p>borderColor</p>
<p>backgroundColor</p>
</div>
</div>
<div id="clockOuterCircle" class="restyleBackground"></div>
Thank you very much in advance
Any better method to remove picker than above mentioned is most welcomed
Try this.
Edit: I removed new ids. HTML remains as yours.
var restyleBG = document.getElementsByClassName("restyleBackground");
restyleBG[0].addEventListener('click', changeBGcolor);
function changeBGcolor() {
let optionChooseBackground = document.getElementById("optionToChooseBackground");
optionChooseBackground.style.display = "block";
let optionToChoosePicker = document.getElementById("optionToChoose");
let colourPicker = document.createElement("input");
colourPicker.type = "color";
colourPicker.className = "colour-picker";
optionToChoosePicker.appendChild(colourPicker);
let optionChooseTag = optionChooseBackground.getElementsByTagName("p")
var varWantToChange = "";
for (let j = 0; j < optionChooseTag.length; j++) {
optionChooseTag[j].addEventListener("click", () => {
varWantToChange = optionChooseTag[j].innerHTML;
});
}
colourPicker.addEventListener('input', function() {
var colorPickerVal = colourPicker.value;
if (varWantToChange === "borderColor") {
restyleBG[0].style.borderColor = colorPickerVal;
} else if (varWantToChange === "backgroundColor") {
restyleBG[0].style.backgroundColor = colorPickerVal;
}
})
}
#optionToChoose {
border: 2px solid red;
width: 200px;
}
#optionToChooseBackground {
position: absolute;
height: 100vh;
width: 100vw;
background-color: rgba(165, 42, 42, 0.205);
display: none;
}
#clockOuterCircle {
display: flex;
justify-content: center;
align-items: center;
width: 42vw;
height: 42vw;
margin: auto;
border-radius: 50%;
border: 4px solid rgb(255, 62, 62);
background-color: rgb(253, 133, 133);
user-select: none;
}
<div id="optionToChooseBackground">
<div id="optionToChoose">
<h3>Choose a style want to change :</h3>
<h4>Border</h4>
<p>borderColor</p>
<p>backgroundColor</p>
</div>
</div>
<div id="clockOuterCircle" class="restyleBackground"></div>
When you open the datepicker You must create a transparent div that fill the screen but below the selector and add the closing event to it.
This is my first piece of code js done on my own. I am trying to have an input field to add items to the list and then if you press the button to generate code it will collect all the checked items and copy the text into another div.
Basically, my question is around two variables:
const list = listUl.children;
const listCopy = listUl.querySelectorAll('span');
Let say I have 4 items in the list. If I add a new item to the list I can see the list.length add this new item, it changes from 4 to 5.
But it doesn't happen with listCopy.length the value keeps being 4.
Why is it happening if lstCopy is inside of list?
How can I have listCopy updated too?
Here is my code:
const addItemInput = document.querySelector('.addItemInput');
const addItemButton = document.querySelector('.addItemButton');
const copyText = document.querySelector('.generateCode');
const listUl = document.querySelector('.list');
const list = listUl.children;
const listCopy = listUl.querySelectorAll('span');
const clonedCode = document.querySelector('.code p');
//FUNCTION: Generate value/items = Draggable, Checkbox, Remove button
const attachItemListButton = (item) => {
//Draggable
item.draggable = "true";
item.classList.add("list--item");
//Checkbox
let checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'checkbox';
checkbox.name = "chkboxName1";
checkbox.value = "value";
checkbox.id = "id";
item.insertBefore(checkbox, item.childNodes[0] || null);
//Remove button
let remove = document.createElement('button');
remove.className = 'remove';
remove.textContent = 'x';
item.appendChild(remove);
};
for (let i = 0; i < list.length; i += 1) {
attachItemListButton(list[i]);
}
//Cloning code if there are checked items
copyText.addEventListener('click', () => {
let copyTextFromList = "";
for (let i = 0; i < listCopy.length; i += 1) {
if (listCopy[i].parentNode.querySelector("input:checked")) {
copyTextFromList += listCopy[i].textContent + ',';
}
}
clonedCode.innerHTML = copyTextFromList;
});
//Add item from the input field to the list
addItemButton.addEventListener('click', () => {
let li = document.createElement('li');
let span = document.createElement('span');
span.textContent = addItemInput.value;
listUl.appendChild(li);
li.appendChild(span);
attachItemListButton(li);
addItemInput.value = '';
});
//FUNCTION: Remove button
listUl.addEventListener('click', (event) => {
if (event.target.tagName == 'BUTTON') {
if (event.target.className == 'remove') {
let li = event.target.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
}
}
});
/* Google fonts */
#import url('https://fonts.googleapis.com/css?family=Heebo:300,400,700');
/* Root */
:root {
--color-white: #fff;
--color-black: #2D3142;
--color-black-2: #0E1116;
--color-gray: #CEE5F2;
--color-gray-2: #ACCBE1;
--color-gray-3: #CEE5F2;
--color-green: #439775;
--color-blue: #4686CC;
}
body {
font-family: 'Heebo', sans-serif;
font-weight: 400;
font-size: 16px;
color: black;
}
h2 {
font-weight: 700;
font-size: 1.5rem;
}
h3 {
font-weight: 700;
font-size: 1.25rem;
}
button {
background: var(--color-blue);
padding: 5px 10px;
border-radius: 5px;
color: var(--color-white);
}
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-drag: element;
-webkit-user-drag: element;
}
ul.list {
list-style-type: none;
padding: 0;
max-width: 300px;
}
.list button {
background: var(--color-black);
}
.list--item {
display: flex;
justify-content: space-between;
align-items: center;
width: auto;
margin: 5px auto;
padding: 5px;
cursor: move;
background: var(--color-gray);
border-radius: 5px;
}
.list--item.draggingElement {
opacity: 0.4;
}
.list--item.over {
border-top: 3px solid var(--color-green);
}
button.remove {
margin: auto 0 auto auto;
}
input#id {
margin: auto 5px auto 0;
}
.button-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
max-width: 300px;
}
.button-wrapper .addItemInput {
width: 63%;
border-radius: 5px 0 0 5px;
}
.button-wrapper .addItemButton {
width: 35%;
border-radius: 0 5px 5px 0;
}
.button-wrapper .generateCode {
width: 100%;
background: var(--color-green);
margin-top: 5px;
}
.code p {
background: var(--color-gray); padding: 5px;
border: 1px solid var(--color-gray-2);
min-height: 20px;
font-weight: 300;
}
<ul class="list">
<li><span>Header</span></li>
<li><span>Hero</span></li>
<li><span>Intro</span></li>
<li><span>Footer</span></li>
</ul>
<div class="button-wrapper">
<input type="text" class="addItemInput" placeholder="Item description">
<button class="addItemButton">Add item</button>
<button class="generateCode">Generate code</button>
</div>
<div class="code">
<h2>Code</h2>
<p></p>
</div>
There are two variants of NodeList, live and non-live ones. querySelectorAll returns a static NodeList that is not live. .children returns a live one (technically it returns an HTMLCollection but you can ignore this distinction for now).
To make listCopy be live as well, you could use listUl.getElementsByTagName('span')…
To select elements by their classes, use getElementsByClassName. There is no way (that I know of) to get a live collection with CSS or XPath (i.e. more complex) queries, though.
The problem is that const listCopy = listUl.querySelectorAll('span'); is initiated with the span array from the beginning.
In order to get updated list
const listCopy = listUl.querySelectorAll('span'); will be let listCopy = listUl.querySelectorAll('span'); and in your function
//Cloning code if there are checked items
copyText.addEventListener('click', () => {
// add the following line - in this way you will select the span from the updated list
listCopy = listUl.querySelectorAll('span');
let copyTextFromList = "";
for (let i = 0; i < listCopy.length; i += 1) {
if (listCopy[i].parentNode.querySelector("input:checked")) {
copyTextFromList += listCopy[i].textContent + ',';
}
}
clonedCode.innerHTML = copyTextFromList;
});
if you want to use querySelectorAll, this maybe help. with this every time you check the length it recalculates and returns the value. Symbol.iterator helps you to manipulate for...of loops.
const addItemInput = document.querySelector('.addItemInput');
const addItemButton = document.querySelector('.addItemButton');
const copyText = document.querySelector('.generateCode');
const listUl = document.querySelector('.list');
const list = listUl.children;
const listCopy = {
get length() {
return listUl.querySelectorAll('span').length
},
*[Symbol.iterator]() {
let i = 0;
const l = listUl.querySelectorAll('span');
while( i < l.length ) {
yield l[i];
i++;
}
}
};
const clonedCode = document.querySelector('.code p');
//FUNCTION: Generate value/items = Draggable, Checkbox, Remove button
const attachItemListButton = (item) => {
//Draggable
item.draggable = "true";
item.classList.add("list--item");
//Checkbox
let checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'checkbox';
checkbox.name = "chkboxName1";
checkbox.value = "value";
checkbox.id = "id";
item.insertBefore(checkbox, item.childNodes[0] || null);
//Remove button
let remove = document.createElement('button');
remove.className = 'remove';
remove.textContent = 'x';
item.appendChild(remove);
};
for (let i = 0; i < list.length; i += 1) {
attachItemListButton(list[i]);
}
//Cloning code if there are checked items
copyText.addEventListener('click', () => {
let copyTextFromList = "";
for (let item of listCopy) {
if (item.parentNode.querySelector("input:checked")) {
copyTextFromList += item.textContent + ',';
}
}
clonedCode.innerHTML = copyTextFromList;
});
//Add item from the input field to the list
addItemButton.addEventListener('click', () => {
let li = document.createElement('li');
let span = document.createElement('span');
span.textContent = addItemInput.value;
listUl.appendChild(li);
li.appendChild(span);
attachItemListButton(li);
addItemInput.value = '';
});
//FUNCTION: Remove button
listUl.addEventListener('click', (event) => {
if (event.target.tagName == 'BUTTON') {
if (event.target.className == 'remove') {
let li = event.target.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
}
}
});
/* Google fonts */
#import url('https://fonts.googleapis.com/css?family=Heebo:300,400,700');
/* Root */
:root {
--color-white: #fff;
--color-black: #2D3142;
--color-black-2: #0E1116;
--color-gray: #CEE5F2;
--color-gray-2: #ACCBE1;
--color-gray-3: #CEE5F2;
--color-green: #439775;
--color-blue: #4686CC;
}
body {
font-family: 'Heebo', sans-serif;
font-weight: 400;
font-size: 16px;
color: black;
}
h2 {
font-weight: 700;
font-size: 1.5rem;
}
h3 {
font-weight: 700;
font-size: 1.25rem;
}
button {
background: var(--color-blue);
padding: 5px 10px;
border-radius: 5px;
color: var(--color-white);
}
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-drag: element;
-webkit-user-drag: element;
}
ul.list {
list-style-type: none;
padding: 0;
max-width: 300px;
}
.list button {
background: var(--color-black);
}
.list--item {
display: flex;
justify-content: space-between;
align-items: center;
width: auto;
margin: 5px auto;
padding: 5px;
cursor: move;
background: var(--color-gray);
border-radius: 5px;
}
.list--item.draggingElement {
opacity: 0.4;
}
.list--item.over {
border-top: 3px solid var(--color-green);
}
button.remove {
margin: auto 0 auto auto;
}
input#id {
margin: auto 5px auto 0;
}
.button-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
max-width: 300px;
}
.button-wrapper .addItemInput {
width: 63%;
border-radius: 5px 0 0 5px;
}
.button-wrapper .addItemButton {
width: 35%;
border-radius: 0 5px 5px 0;
}
.button-wrapper .generateCode {
width: 100%;
background: var(--color-green);
margin-top: 5px;
}
.code p {
background: var(--color-gray); padding: 5px;
border: 1px solid var(--color-gray-2);
min-height: 20px;
font-weight: 300;
}
<ul class="list">
<li><span>Header</span></li>
<li><span>Hero</span></li>
<li><span>Intro</span></li>
<li><span>Footer</span></li>
</ul>
<div class="button-wrapper">
<input type="text" class="addItemInput" placeholder="Item description">
<button class="addItemButton">Add item</button>
<button class="generateCode">Generate code</button>
</div>
<div class="code">
<h2>Code</h2>
<p></p>
</div>
How to insert a new node(create with javascript) under the clicked node?.
At the moment it crosses the original div, I do not want that it crosses, it should remain in its origin
let parent = document.getElementById("parent");
parent.addEventListener("click", function(event) {
var currentSelection, currentRange, currentNode, newDiv, newContent;
currentSelection = window.getSelection();
currentRange = currentSelection.getRangeAt(0);
currentNode = currentRange.startContainer;
console.log(currentNode.nodeValue);
newDiv = document.createElement("div");
newDiv.className = 'nuevo';
newContent = document.createTextNode("holanda");
newDiv.appendChild(newContent);
this.appendChild(newDiv)
});
.nuevo {
width: auto;
height: auto;
background: red;
display: inline-block;
margin-top: 1em;
z-index: 3;
}
#parent>div {
float: left;
z-index: 1;
}
<div id="parent" contenteditable=true style="border: black 2px solid; height:200px">
<div>hello</div>
<div> *** </div>
<div>world</div>
</div>
result:
when clicked the word world
when clicked the word ***
Utilizing the offsetLeft property to locate new append elements:
let parent = document.getElementById("parent");
let rootElements = document.querySelectorAll("div.root");
for (let i = 0; i < rootElements.length; i++ ) {
rootElements[i].addEventListener("click", function(event) {
var currentSelection, currentRange, currentNode, newDiv, newContent;
currentSelection = window.getSelection();
currentRange = currentSelection.getRangeAt(0);
currentNode = currentRange.startContainer;
// console.log(currentNode.nodeValue);
newDiv = document.createElement("div");
newDiv.className = 'nuevo';
newContent = document.createTextNode("holanda");
newDiv.appendChild(newContent);
let xPos = event.currentTarget.offsetLeft;
let newEle = parent.appendChild(newDiv);
newEle.style.left = xPos + "px";
});
}
#parent {
position: relative;
left: 0px;
}
.nuevo {
display: block;
width: fit-content;
height: auto;
background: red;
position: relative;
}
.root {
vertical-align: top;
display: inline-block;
}
<div id="parent" contenteditable=true style="border: black 2px solid; height:200px">
<div class = "root">hello</div>
<div class = "root">***</div>
<div class = "root">world</div>
</div>
Update: one more way to achieve the goal
Append every new stack which actually has the same number of elements as first line. Utilize display: flex property on every new stack, and then give the inner elements corresponding width as same as their ancestor by flex-basis (why not width? this is another problem because of characteristic of flex property).
And let content of that only element which we want for visibly appending to extend the space for itself.
let parent = document.getElementById("parent");
let rootElements = document.querySelectorAll("div.root");
for (let i = 0; i < rootElements.length; i++ ) {
rootElements[i].addEventListener("click", function(event) {
newStack = document.createElement("div");
newStack.className = 'stack';
for (let j = 0; j < rootElements.length; j++) {
let grid = document.createElement("div");
grid.className = 'flexItem';
grid.setAttribute("style", "flex-basis:" + rootElements[j].getBoundingClientRect().width + "px");
if (i===j) {
grid.className += ' nuevo';
grid.textContent = 'holanda';
}
newStack.appendChild(grid)
}
parent.appendChild(newStack);
});
}
#parent {
font-size: 0px; // For eliminating gap between inline-blocks
}
.stack {
display: flex;
}
.flexItem {
flex: 0 1;
}
.nuevo {
height: auto;
background: red;
position: relative;
font-size: 16px;
}
.root {
display: inline-block;
font-size: 16px;
}
<div id="parent" contenteditable=true style="border: black 2px solid; height:200px">
<div class = "root">hello</div>
<div class = "root">*******</div>
<div class = "root">world</div>
</div>
Attach the event listener to each one of the divs inside parent so that you can use them to append your elements, also, change the display property of nuevo to block
let items = document.querySelectorAll("#parent > div");
for (var i = 0; i < items.length; i++) {
var item = items[i];
item.addEventListener("click", function(event) {
var newDiv = document.createElement("div");
newDiv.className = 'nuevo';
newDiv.appendChild(document.createTextNode("holanda"));
newDiv.style.left = this.offsetLeft + 'px';
this.parentNode.appendChild(newDiv);
});
}
.nuevo {
width: auto;
height: auto;
background: red;
display: block;
clear: both;
position: relative;
}
#parent>div {
float: left;
}
#parent {
position: relative;
left: 0px;
}
<div id="parent" contenteditable=true style="border: black 2px solid; height:200px">
<div>hello</div>
<div> *** </div>
<div>world</div>
</div>
I have tried using the following on my flex-container after clicking on my button to generate the content, but when I resize the windows, it keeps resizing my items. I want them to have a fixed width and height (ideally each item would be a square of 100x100 px)
flex-shrink: 0;
flex-grow: 0;
const sampleContent = ["stuff1", "stuff2", "stuff3", "stuff4", "stuff5"]
const button = document.querySelector(".content");
const rootElement = document.querySelector("#root");
const widthDiv = document.querySelector("#width-value");
const resultContainer = document.querySelector("#root");
const widthValue = window.getComputedStyle(resultContainer, null).getPropertyValue("width");
button.addEventListener("click", () => {
sampleContent.forEach((content) => {
const newDiv = document.createElement("div");
console.log(newDiv);
newDiv.textContent = content;
newDiv.classList.add("result");
rootElement.appendChild(newDiv);
})
})
widthDiv.textContent = widthValue;
.result-container {
display: flex;
width: 60%;
height: 200px;
border: 1px black solid;
flex-wrap: nowrap;
}
.container {
display: flex;
justify-content: center;
}
.result {
width: 100px;
height: 100px;
border: 1px dotted pink;
margin: 1%;
}
<div class="container">
<div id="root" class="result-container">
</div>
</div>
<button class="content">
Generate Content from API
</button>
<div id="width-value">
</div>
An initial setting on flex items is flex-shrink: 1. That means that items can shrink to avoid overflowing the container. Add flex-shrink: 0 to the items and you're all set.
const sampleContent = ["stuff1", "stuff2", "stuff3", "stuff4", "stuff5"]
const button = document.querySelector(".content");
const rootElement = document.querySelector("#root");
const widthDiv = document.querySelector("#width-value");
const resultContainer = document.querySelector("#root");
const widthValue = window.getComputedStyle(resultContainer, null).getPropertyValue("width");
button.addEventListener("click", () => {
sampleContent.forEach((content) => {
const newDiv = document.createElement("div");
console.log(newDiv);
newDiv.textContent = content;
newDiv.classList.add("result");
rootElement.appendChild(newDiv);
})
})
widthDiv.textContent = widthValue;
.result-container {
display: flex;
width: 60%;
height: 200px;
border: 1px black solid;
flex-wrap: nowrap;
}
.container {
display: flex;
justify-content: center;
}
.result {
flex: 0 0 100px;
/* fg: 0, fs: 0, fb: 100px */
/* width: 100px; */
height: 100px;
border: 1px dotted pink;
margin: 1%;
}
<div class="container">
<div id="root" class="result-container"></div>
</div>
<button class="content">Generate Content from API</button>
<div id="width-value"></div>