Home > Software design >  Add event listeners to newly create buttons
Add event listeners to newly create buttons

Time:10-01

html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>View Review</title>
    <link rel="stylesheet" href="style.css" />
  </head> 

  <body>
    <div class="content">
      <h1 id = "ourReview">Our Reviews</h1>
    </div>
  </body>
  <script src="app.js"></script>
  <script src="script.js"></script>
</html>

data

const reviews = [
    {
      id: 1,
      name: "susan smith",
      job: "web developer",
      img:
        "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883334/person-1_rfzshl.jpg",
      text:
        "I'm baby meggings twee health goth  1. Bicycle rights tumeric chartreuse before they sold out chambray pop-up. Shaman humblebrag pickled coloring book salvia hoodie, cold-pressed four dollar toast everyday carry",
    },
    {
      id: 2,
      name: "anna johnson",
      job: "web designer",
      img:
        "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883409/person-2_np9x5l.jpg",
      text:
        "Helvetica artisan kinfolk thundercats lumbersexual blue bottle. Disrupt glossier gastropub deep v vice franzen hell of brooklyn twee enamel pin fashion axe.photo booth jean shorts artisan narwhal.",
    },
    {
      id: 3,
      name: "peter jones",
      job: "intern",
      img:
        "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883417/person-3_ipa0mj.jpg",
      text:
        "Sriracha literally flexitarian irony, vape marfa unicorn. Glossier tattooed 8-bit, fixie waistcoat offal activated charcoal slow-carb marfa hell of pabst raclette post-ironic jianbing swag.",
    },
    {
      id: 4,
      name: "bill anderson",
      job: "the boss",
      img:
        "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883423/person-4_t9nxjt.jpg",
      text:
        "Edison bulb put a bird on it humblebrag, marfa pok pok heirloom fashion axe cray stumptown venmo actually seitan. VHS farm-to-table schlitz, edison bulb pop-up 3 wolf moon tote bag street art shabby chic. ",
    },
  ];

js

const ourReview = document.getElementById("ourReview");
let count = 0;
const divElem = document.createElement("div");
 
function loadPerson(personNum, arr = reviews) {
  divElem.className = "review-modal";
  divElem.innerHTML = `
    <img src="${arr[personNum].img}" alt="${arr[personNum].name}"/>
    <h2>${arr[personNum].name}</h2>
    <span>${arr[personNum].job}</span>
    <p>${arr[personNum].text}</p>
    <div id="arrow-button">
    <button id="frd-btn"><</button>
    <button id="bck-btn">></button>
    </div>
    <button id="suprise">Suprise me</button>
    </div>`;
  ourReview.parentNode.append(divElem);
}
window.addEventListener("DOMContentLoaded", loadPerson(0));

// here these let constants are not registering new values by new modal
let frdBtn = document.getElementById("frd-btn");
let bckBtn = document.getElementById("bck-btn");
let suprise = document.getElementById("suprise");

frdBtn.addEventListener("click", () => {
  if (count == 0) {
    count = reviews.length - 1;
  }
  count--;
  loadPerson(count);
});
bckBtn.addEventListener("click", () => {
  if (count > reviews.length - 1) {
    count = 0;
  }
  count  ;
  loadPerson(count);
});

suprise.addEventListener("click",() => {
  const randomNum = Math.floor(Math.random()*reviews.length)
  console.log(randomNum);
  loadPerson(randomNum);
})

In the above code I am trying

 let frdBtn = document.getElementById("frd-btn");
 let bckBtn = document.getElementById("bck-btn");
 let suprise = document.getElementById("suprise");

update these variable and trigger event listeners to the new button but frdBtn ,bckBtn ,suprise are not updating and eventlistners are binded to original buttons which are create on window.addEventListener("DOMContentLoaded", loadPerson(0));

CodePudding user response:

There are several problems in your code.

First you have to provide a function as a parameter of window.addEventListener. You are currently passing the return value of the function after it has executed, which is not want you want:

window.addEventListener("DOMContentLoaded", () => loadPerson(0));

After that, you should move the event listeners inside the loadPerson function because otherwise they execute before the elements exist (they are being added asynchronously).

Last thing you should do: don't identify nodes with an id when there are several copies of them (several persons). That makes the HTML invalid and in that case document.getElementById retrieves the first matching element only.

Also, the const divElem = document.createElement("div"); should go inside loadPerson as well. Otherwise you remove it from where it was, before appending it again.

You could for example use document.createElement('button') then attach an event listener and then append them to divElem. And if there is CSS applied with an #id selector, use classes instead.

CodePudding user response:

So multiple things wrong here.

First of all your DOMContentLoaded loaded event isn't executing how you think it is.

window.addEventListener("DOMContentLoaded", loadPerson(0));

You're calling loadPerson and assigning the returned value (which will be undefined as you don't return anything from the loadPerson function) and assigning that as the action to trigger when DOMContentLoaded event occurs.

Change it to

window.addEventListener("DOMContentLoaded", () => loadPerson(0));

This will call the anonymous function when DOMContentLoaded event triggers.

Secondly, your code is applying your event listeners on the first run of the script. Which actually only works because of your mistake with the DOMContentLoaded issue described above.

You need to action all of your code on DOMContentLoaded event (to be honest, it's easier and better practice to just ensure your JS script file is the last element to be loaded on the page).

Now with your buttons and their logic. You need to know that JS event listeners aren't "persistent" aka if you create a new button, you need to tell JS to apply the listener to your newly created button.

If I were you, I'd create the elements programatically, not manually typing out the HTML elements as a value of innerHTML. Aka

  divElem.className = "review-modal";
  divElem.innerHTML = `
    <img src="${arr[personNum].img}" alt="${arr[personNum].name}"/>
    <h2>${arr[personNum].name}</h2>
    <span>${arr[personNum].job}</span>
    <p>${arr[personNum].text}</p>
    <div id="arrow-button">
    <button id="frd-btn"><</button>
    <button id="bck-btn">></button>
    </div>
    <button id="suprise">Suprise me</button>
    </div>`;
  ourReview.parentNode.append(divElem);

Can be

divElem.classList.add('review-modal');

const elements = {
    img: document.createElement('img'),
    name: document.createElement('h2'),
    job: document.createElement('span'),
    text: document.createElement('p'),
    buttonContainer: document.createElement('div'),
    buttons: {
        frd: document.createElement('button'),
        bck: document.createElement('button'),
        surprise: document.createElement('button')
    }
}

elements.img.setAttribute('src', arr[personNum].img);
elements.img.setAttribute('alt', arr[personNum].name);

elements.name.innerText = arr[personNum].name;
elements.job.innerText = arr[personNum].job;
elements.text.innerText = arr[personNum].text;

elements.buttonContainer.id = 'arrow-button';

elements.buttons.frd.innerText = '<';
elements.buttons.frd.addEventListener('click', () => {

    // Logic Here
});

elements.buttons.bck.innerText = '>';
elements.buttons.bck.addEventListener('click', () => {

    // Logic Here
});

elements.buttons.surprise.id = 'surprise';
elements.buttons.surprise.addEventListener('click', () => {

    // Logic Here
});

elements.buttonContainer.append(...Object.values(elements.buttons));

divElem.append(
    elements.img, 
    elements.name, 
    elements.job, 
    elements.text, 
    elements.buttonContainer
);

ourReview.parentNode.append(divElem);

This should go into a function that handles the creation of these elements. Additionally ALL id attributes must be unique regardless of anything. You could either switch these to JS relevant class names (aka prepended with js-- or something you can identify as JS related) or just ensure the ID's are unique (append with a number). I don't advise the latter as it can get confusing.

  • Related