Home > Net >  Button Functionality in JS
Button Functionality in JS

Time:12-09

I created A simple Website for basic add/remove friend.

But the button is only working in first box and not working in other two boxes.

Button is completly working in first box but second and button button is not responding

Edit - All the buttons only changing the first box text

var arr = [{
    name: "Raju",
    image: "./1.jpg",
    status: "Stranger"
  },
  {
    name: "Shyam",
    image: "./2.jpg",
    status: "Stranger"
  },
  {
    name: "Babu Bhaiya",
    image: "./3.jpg",
    status: "Stranger"
  },
];

var cluster = "";
arr.forEach(function(val) {
  cluster = cluster   ` 
    <div id="card"> 
    <img src="${val.image}" alt="">
    <h1>${val.name}</h1>
    <p>${val.status}</p>
    <button>Send Request</button>
    </div>
  `;
});

//Botton Functionality
document.getElementById("cluster").innerHTML = cluster;

const btn = document.querySelectorAll("button");
var fact = 0;

btn.forEach((btn) => {
  btn.addEventListener("click", function() {
    if (fact == 0) {
      var timer = setTimeout(() => {
        document.querySelector("p").textContent = "Friend";
        document.querySelector("p").style.color = "rgb(66, 178, 113";
        document.querySelector("button").textContent = "Cancel";
      }, 2000);
      fact = 1;
      document.querySelector("p").textContent = "Request Pending";
      document.querySelector("button").textContent = "Send Request";
    } else {
      clearTimeout(timer);
      fact = 0;
      document.querySelector("p").textContent = "Strenger";
      document.querySelector("p").style.color = "rgb(221, 66, 66)";
      document.querySelector("button").textContent = "Send Request";
      fact = 0;
    }
  });
  });
<div >
  <div id="cluster" ></div>
</div>

Image

CodePudding user response:

Instead of attaching listeners to all of the buttons you can use event delegation and attach one listener to a containing element that can listen out for events from its children as they "bubble up" the DOM.

In this example when a button is clicked we destructure out its previousElementSibling (the paragraph element), and its textContent. And then based on the textContent perform the operations.

(I've also used a switch statement instead of flags which makes the code a little cleaner, and map to produce the HTML rather than forEach.)

const arr=[{name:"Raju",image:"./1.jpg",status:"Stranger"},{name:"Shyam",image:"./2.jpg",status:"Friend"},{name:"Babu Bhaiya",image:"./3.jpg",status:"Request Pending"}];

// `map` over the array and produce an array of
// strings which is `joined` up at the end of the iteration
const html = arr.map(obj => {
  return ` 
    <div id="card"> 
    <img src="${obj.image}" alt="">
    <h3>${obj.name}</h3>
    <p>${obj.status}</p>
    <button type="button">Send Request</button>
    </div>
  `;
}).join('');

// Cache the container/cluster elements
const cluster = document.querySelector('#cluster');
const container = document.querySelector('.container');

// Add the event listener to the container
container.addEventListener('click', handleClick);

// Add the HTML to the cluster element
cluster.innerHTML = html;

// When the listener catches an event...
function handleClick(e) {
  
  // ...first check that it's a button...
  if (e.target.matches('button')) {
    
    // ...destructure the previous element sibling
    // element (relabeling it as `para`), and the textContent
    // from the clicked element
    const {
      previousElementSibling: para,
      textContent
    } = e.target;

    // Depending on the text content value
    // choose the path to take
    switch (textContent) {
      
      case 'Send Request': {
        para.textContent = 'Request Pending';
        e.target.disabled = true;
        setTimeout(() => {
          para.textContent = 'Friend';
          para.className = 'friend';
          e.target.textContent = 'Cancel';
          e.target.disabled = false;
        }, 2000);
        break;
      }
      
      case 'Cancel': {
        para.textContent = 'Strenger';
        para.className = 'strenger';
        e.target.textContent = 'Send Request'      
        break;
      }
    
    }
  
  }

}
.friend { color: rgb(66, 178, 113); }
.strenger { color: rgb(221, 66, 66); }
<div >
  <div id="cluster" ></div>
</div>

Additional documentation

CodePudding user response:

You are using document.querySelector() which will only select the first matched item.

According to MDN

The Document method querySelector() returns the first Element within the document that matches the specified selector, or group of selectors.

Instead what you need is querySelectorAll

const buttons = userList.querySelectorAll("button");

buttons.forEach((btn) => {
  btn.addEventListener("click", function() {
    //...
  }
});

Edit:

All buttons changing the first text is the same issue as querySelector. It can be fixed by scoping it.

const buttons = userList.querySelectorAll("button");

buttons.forEach((btn) => {
  btn.addEventListener("click", function() {
    btn.querySelector(":scope > p").textContent = "Friend";
    // ...
  }
});
  • Related