To get a job as a front end developer, we need to nail the coding interview.
In this article, we’ll look at some harder questions about DOM manipulation and handling events.
What is a repaint and when does this happen?
A repaint happens when we change the look of an element without changing its size and shape.
It doesn’t cause reflow since its dimensions and position didn’t change.
The repainting process happens when an element changes the background color, change text color, or hide visibility.
How could we run some JavaScript when DOM is ready like $(document).ready
?
We can put our scripts in the HTML body element. The DOM would be ready by the time the browser runs the script tag there.
Also, we can put our code inside the DOMContentLoaded
event handler. The code inside will run only when the DOM is completely loaded.
For example, we can write the following:
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM loaded');
});
We can also watch the readystatechange
event by attaching a listener to it.
When the readyState
is 'complete'
, then we know the DOM has loaded.
For instance, we can write the following code to do that:
document.onreadystatechange = () => {
if (document.readyState == "complete") {
console.log('DOM loaded');
}
}
What is event bubbling? How does event flow?
Event bubbling means that the event propagates from the originating element to its parent, grandparent, and all the way up to the window
object.
The browser will run all event handlers that are attached to all the parent elements of the originating element in addition to the originating element.
For example, if we have the following HTML:
<div>
<p>
<button>Click</button>
</p>
</div>
Then when we attach event listeners to all the elements and document
and window
as follows:
const div = document.querySelector('div');
const p = document.querySelector('p');
const button = document.querySelector('button');
button.onclick = () => {
alert('button clicked');
}
p.onclick = () => {
alert('p clicked');
}
div.onclick = () => {
alert('div clicked');
}
document.onclick = () => {
alert('document clicked');
}
window.onclick = () => {
alert('window clicked');
}
and click the Click button, then we’ll see all the alerts listed in the same order that we listed in the code.
So we get ‘button clicked’, ‘p clicked’, ‘div clicked’, ‘document clicked’ and ‘window clicked’ alerts displayed in that order.
How would we destroy multiple list items with one click handler?
We can use event delegation to do that.
It works by listening to the clicks of the parent element of the list. Then we can check which child has been clicked in the click handler and then remove that element from the DOM.
For example, if we have the following HTML:
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
<li>forth</li>
<li>Fifth</li>
</ul>
Then we can write the following JavaScript code to remove the li elements that we clicked on as follows:
document.querySelector('ul').addEventListener('click', (e) => {
const elm = e.target.parentNode;
elm.removeChild(e.target);
e.preventDefault();
});
In the code above, we get the parentNode
property of the element we clicked on to get the ul.
Then we can call removeChild
on it to remove the li that we clicked on since e.target
is the element that we clicked on, which is the li.
Finally, we call preventDefault
to stop event propagation.
Create a button that is destroyed by clicking on it but two new buttons are created in its place.
We can do that by using the logic above for removing the button that we clicked on.
Then we add use createElement
and appendChild
to create more buttons and add them to the list.
For example, given the following HTML:
<div>
<button>button</button>
</div>
We write the following JavaScript code to add 2 buttons and then remove the original button that was clicked on by attaching a click listener to the div and then manipulating the buttons:
document.querySelector('div').addEventListener('click', (e) => {
if (e.target.tagName === 'DIV') {
return;
}
const elm = e.target.parentNode;
e.preventDefault();
const btn = document.createElement('button');
btn.innerHTML = 'button';
const btn2 = document.createElement('button');
btn2.innerHTML = 'button';
elm.appendChild(btn);
elm.appendChild(btn2);
elm.removeChild(e.target);
});
In the code above, we check if we actually clicked on a button.
If we did, then we proceed to create 2 buttons. Then we call appendChild
on the parentNode
of the button that was clicked, which is the div, to attach the 2 buttons.
Then we call removeChild
on e.target
, which should the button since we checked it’s not a div, to remove the button.
Conclusion
We can watch if the DOM is ready with readystatechange
or DOMContentLoaded
events.
Event bubbling happens when an element’s events propagate up the DOM tree.
appendChild
and removeChild
are used to add and remove elements. We can handle events of multiple child elements with event delegation.
A repaint happens when we change the look of an element without changing its geometry.