I need your help. My task is to create 100 divs with pure JavaScript. Each div should have the following functionality: Each div has its own name, like div1, div2, div3 and up to 100. For instance, I click on div31, div45, div89, they move to the top. Now the order of my elements is as follows:
div89, div45, div31, div1, div2
at the places where I took the div data
- div30 – div32 – div33
- div43 -div44 – div46
- div88 – div90 – div91
When I click again on the moved up items, they should return to their previous positions.
The problem is that when I click on the elements that have risen for me, they return, but in arbitrary places. That is, instead of going back, in our example div30, div31, div32, div33, our div31 can be anywhere. Tell me what is my mistake? Thank you very much
document.addEventListener('DOMContentLoaded', function() {
for (let i = 1; i <= 100; i++) {
const div = document.createElement('div');
div.className = 'div-element';
div.textContent = 'div' + i;
document.body.appendChild(div);
}
const originalPositions = Array.from(document.getElementsByClassName('div-element')).map((div, index) => index);
const divElements = document.getElementsByClassName('div-element');
for (let i = 0; i < divElements.length; i++) {
const div = divElements[i];
let isFirstPosition = false;
let originalPosition = -1;
div.addEventListener('click', function() {
if (!isFirstPosition) {
document.body.insertBefore(div, document.body.firstElementChild);
isFirstPosition = true;
originalPosition = i;
} else {
const referenceDiv = divElements[originalPositions[originalPosition]];
document.body.insertBefore(div, referenceDiv.nextElementSibling);
isFirstPosition = false;
}
});
}
});
>Solution :
You should not append to the <body>. This makes it much harder to move elements around. You should create a container element to hold them.
Now, you should use the dataset property for each element to store stateful information like original index and if the element has moved. Note that values in the dataset are always retrieved as strings. You will need to convert them back into boolean and integer values to do comparisons.
When reverting back to the original position, you should loop backwards.
const findRefEl = (container, index) => {
const targetIndex = +index; // Cast to a number
// Loop backwards
for (let i = container.children.length - 1; i >= 0; i--) {
const currentIndex = +container.children[i].dataset.originalIndex;
if (currentIndex < targetIndex) {
return container.children[i];
}
}
return container.children[0]; // Default to the first
}
const handleMove = (e) => {
const div = e.target, containerEl = div.closest('.container');
if (div.dataset.moved === 'false') {
containerEl.insertBefore(div, containerEl.firstElementChild);
div.dataset.moved = 'true';
} else {
const ref = findRefEl(containerEl, div.dataset.originalIndex);
containerEl.insertBefore(div, ref.nextElementSibling);
div.dataset.moved = 'false';
}
}
document.addEventListener('DOMContentLoaded', function() {
const containerEl = document.querySelector('.container');
for (let i = 0; i < 100; i++) {
const div = document.createElement('div');
div.className = 'div-element';
div.textContent = `div${i + 1}`;
div.dataset.originalIndex = i.toString(); // Track the original index
div.dataset.moved = false; // Track if it has been moved
div.addEventListener('click', handleMove);
containerEl.appendChild(div);
}
});
.div-element {
border: thin solid grey;
min-width: 4rem;
max-width: 4rem;
text-align: center;
cursor: pointer;
}
.div-element:hover {
background: yellow;
}
.div-element[data-moved="true"] {
font-weight: bold;
}
<div class="container"></div>