How to access to dynamically created DOM elements - Event delegation/Event bubbling/Event propagation
Tags: eventdelegation, eventbubbling, eventpropagation, javascript
Published: 2022-06-29 17:08:18

While I was working on my project, I needed to get an access to elements that are created dynamically. Because I wanted to implement social media app that user can create posts, edit and delete. But I faced a problem. Because dynamically created elements can't be selected the way I did normally. If I was going to select a DOM element, I would use either querySelector or getElementById and something like that. Then I will add an event listener to interact. But because they are dynamically created, it does not exist in the html in the beginning. It gets created by JavaScript and gets added after.
So you will find an error saying that element doesn't exist.
Or this will throw an error of addEventListener of null.

When the user enters to the website it will download, read, execute files like html, css and JavaScript. But on page load, dynamically created DOM elements are not there yet. It will be created and be seen when the browser receives the data from API/server or when user writes a new post(because the post only gets created when there’s data) and that's after the initial page load.

Then how can I select those elements so that I can interact with them?
I solved this problem with event delegation. I wasn't really sure how to work with this when I only learnt the theory.
But it became more clear how it works when I actually used this to solve the issue I had.


## Event Propagation / Event Delegation / Event Bubbling

What is Event Propagation?
"Event Propagation is a mechanism that defines how events propagate or travel through the DOM tree to arrive its target and what happens to it afterward."(https://www.tutorialrepublic.com/javascript-tutorial/javascript-event-propagation.php)

Event Delegation - is a special way to handle events, in which an event handler of the parent of an element handles events for that element. This is a way of taking advantage of event bubbling.
Document events or document element events **bubble up the DOM tree** and they trigger event handlers of its ancestors. For example, if an event happens by clicking `<li>`, a child node of `<ul>`, this event will be propagated to `<ul>`, the parent node which means parent node can detect the events that happened to their children. (And also, child node can detect the event that happened to their parents as well.)
So, the event bubbling provides alternative way to handle events.

The image below shows you how event propagate -
click on `<td>` inside a table, taken from the specification:

![event-propagation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8dodmlyf6h9qsxls67fv.png)
<figcaption>Source -https://javascript.info/bubbling-and-capturing</figcaption>
&nbsp;

The standard DOM Events describes 3 phases of event propagation:
Capturing phase – the event **goes down to the element**.
Target phase – the event **reached the target** element.
Bubbling phase – the **event bubbles up** from the element.

So, the event propagates through the DOM tree, which means we can catch the target within the DOM tree not only the selected target. 
But if you want to stop event being propagated, then use event.stopPropagation()  
&nbsp;
   
## How I solved my issue using event delegation.

```javascript
// 이벤트 위임 - 상위요소에 이벤트를 주면 하위요소까지 다 접근 가능!
const app = document.querySelector("#app");
// 모달 버튼 & 좋아요 클릭 핸들링 
let commentClickedIndex;
let isMyComment = false;
const handleDomClick = (event) => {
  const clickedBtn = event.target;
  if(clickedBtn.classList.contains("setting-logout-btn")){
    openModal(clickedBtn);
  } else if(clickedBtn.classList.contains("post-edit-btn")){
    openModal(clickedBtn);
  } else if(clickedBtn.classList.contains("comment-edit-btn")) {   
    const buttons = document.querySelectorAll(".comment-edit-btn");
    const index = [...buttons].indexOf(clickedBtn)
    commentClickedIndex = index;
    commentAuthorId = commentsListArr[index].author._id;
    // 클릭한 댓글이 내가 쓴 댓글인 경우
    if(commentAuthorId === userId) {
      isMyComment = true;
      openModal(clickedBtn);
    } else {
      isMyComment = false;
      openModal(clickedBtn);
    }
  } else if(clickedBtn.id === "likebtn") {
    applyLike(clickedBtn);
  }

}
app.addEventListener("click", handleDomClick)
```
The code above is some part that used for my project. I wanted to be able to add events to different elements inside my app since I created what's inside "app" dynamically. so I used event listener to the most outer element which is an *app then checked if it contains certain class to know what that element is exactly, to do specific things for each element.

### ** There are exceptions for event bubbling.
The following document element events don't bubble up: focus, blur, scroll, load/unload and mouse event(mouseenter, mouseleave)