LoneWolf
LoneWolf

Reputation: 86

Is there a way to uniquely identity a dynamically added element?

I am trying to dynamically load a bunch of posts from a API and then implement a like button for each of them.

function load_allposts(){
    fetch("/posts")
    .then(response => response.json())
    .then(posts => {
        var enc = document.createElement('div');
        enc.className = "post-enc";
        let s = ``;
        posts.forEach(element => {
            s += `<div class="p-container">
                    <div>
                        <button type="button" class="btn btn-link" class="profile-btn" data-id=${element[0].author_id}> ${element[0].author_name} </button>
                    </div>
                    <div class="post-body">
                        ${element[0].body}
                    </div>
                    <div class="p1">
                        <span class="like-status">${element[0].likes}</span>  people like this
                        <button class="like-btn">${element[1]}</button>
                    </div>
                    <div class="post-time">
                        ${element[0].timestamp}
                    </div>
                </div>`;
        });
        enc.innerHTML = s;
        document.querySelector('#all-posts').appendChild(enc);
    });
}

I would to like to modify the <span class="like-status"> element when I click the <button class="like-btn">. The only way that I can think of to get a reference to <span class="like-status"> is by adding a ID to it by implementing some kind of counter, which I feel is more like a hack rather than real solution.

I tried googling but almost all solutions involved JQuery, which I am not familiar with. Any help would be appreciated.

Upvotes: 0

Views: 68

Answers (1)

Karan
Karan

Reputation: 12619

You can use delegate event binding document.addEventListener('click', function(event) { to trigger click event for dynamically added button.

It will raise click on every element inside document you need to find if it is one which you expect with event.target.matches('button.like-btn').

Then you can find your span with getting parent and then finding span.like-status using querySelector.

Try it below. For demo modified load_allposts. You do not need to do any change in it.

load_allposts();

document.addEventListener('click', function(event) {
  if (event.target.matches('button.like-btn')) {
    let span = event.target.parentElement.querySelector('span.like-status');
    span.innerText = 'Modified';
  }
});

function load_allposts() {

  let posts = [1]
  var enc = document.createElement('div');
  enc.className = "post-enc";
  let s = ``;
  posts.forEach(element => {
    s += `<div class="p-container">
                    <div>
                        <button type="button" class="btn btn-link" class="profile-btn" data-id=element[0].author_id> element[0].author_name </button>
                    </div>
                    <div class="post-body">
                        element[0].body
                    </div>
                    <div class="p1">
                        <span class="like-status">element[0].likes</span>  people like this
                        <button class="like-btn">element[1]</button>
                    </div>
                    <div class="post-time">
                        element[0].timestamp
                    </div>
                </div>`;
  });
  enc.innerHTML = s;
  document.querySelector('#all-posts').appendChild(enc);
}
<div id='all-posts'>
</div>


Note event delegation have extra overhead so alternatively you can use below code.

Here added two functions added as below and added one line bindClickEvent(enc); at end of load_allposts function.

  • likeClick - perform custom logic to update span.like-status
  • bindClickEvent - bind click event to all button.like-btn inside div
  • Call bindClickEvent(enc); at end of load_allposts function.

Try it below.

load_allposts();

// perform custom logic to update span.like-status
function likeClick(event) {
  // querySelector will return first matching element
  let span = event.target.parentElement.querySelector('span.like-status');
  span.innerText = 'Modified';
}

// bind click event to all button.like-btn inside div
function bindClickEvent(enc) {
  // querySelectorAll will return array of all matching elements
  let buttons = enc.querySelectorAll('button.like-btn');
  // loop over each button and assign click function
  for (let i = 0; i < buttons.length; i++) {
    buttons[i].onclick = likeClick;
  }
}

function load_allposts() {

  let posts = [1]
  var enc = document.createElement('div');
  enc.className = "post-enc";
  let s = ``;
  posts.forEach(element => {
    s += `<div class="p-container">
                    <div>
                        <button type="button" class="btn btn-link" class="profile-btn" data-id=element[0].author_id> element[0].author_name </button>
                    </div>
                    <div class="post-body">
                        element[0].body
                    </div>
                    <div class="p1">
                        <span class="like-status">element[0].likes</span>  people like this
                        <button class="like-btn">element[1]</button>
                    </div>
                    <div class="post-time">
                        element[0].timestamp
                    </div>
                </div>`;
  });
  enc.innerHTML = s;
  document.querySelector('#all-posts').appendChild(enc);

  // assign click event to buttons inside enc div.
  bindClickEvent(enc);
}
<div id='all-posts'>
</div>

Upvotes: 1

Related Questions