Several days ago I worked on a task where the solution was to create some elements in the DOM tree in one container and then move them to another. What I liked about it is how easy it can be done. I would like to describe some kind of fixed todo-list implementation as an example in my current post. If you like you may just check the extended code here: https://stackblitz.com/edit/moving-elements-through-dom-tree?file=index.html.
Page markup
First let’s check the HTML structure of the page: block to store undone tasks, block to store done tasks and the button to move task from one list to another:
<div id="undone">
<div class="task">
<div class="header">Clean the room</div>
<div class="description">Make the bed, put books on the shelf, vacuum the floor.</div>
</div>
<div class="task">
<div class="header">Do the home work</div>
<div class="description">Math, English, Physics</div>
</div>
</div>
<div id="done">
</div>
<button onclick="done()">Done</button>
The task consists of two parts: header and description. By default description is hidden. Also lists have different text color and default cursor for task header is switched to pointer:
#undone .task .header { color: red; }
#done .task .header { color: green; }
.header { cursor: pointer; }
.description { display: none; }
Toggling description visibility
The function for toggling description is based on the target property of the Event object which is passed to the listener.
function showDescription(event) {
const description = event.target.parentNode.querySelector('.description');
if (description)
description.style.display =
description.style.display == 'block' ? '' : 'block';
}
Here if we could find the description element next to the header we are switching the display CSS property. After page is loaded the function is assigned to each task header element as onclick event handler:
document.addEventListener('DOMContentLoaded', () =>
document
.querySelectorAll(".task .header")
.forEach((header) => header.addEventListener('click', showDescription))
);
More clever would be to assign the listener to the whole list (in real projects it will increase performance when there are lots of elements) but I intentionally have done it this way to demonstrate that after moving the element the event listener is not gone.
Moving element
Finally, function which move the first task from the list of undone task to the list of done ones:
function done() {
const task = document.getElementById("undone").querySelector('.task');
if (task) document.getElementById("done").appendChild(task);
}
So to move elements from one place to another in the DOM tree all is needed is just to use the appendChild method of the new parent node. When this method is used browser just reset the link to parent node for moved element.
The described example is very basic just to demonstrate browser behavior. On top of it any other logic of element manipulation can be done, e.g. blocks shuffling or creating paired lists. As an alternative cloning the node might be an option, but in this case the clone will lose all event listeners and they should be assigned once again. Depending on the situation one or another solution might be suitable.