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>
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";
// ...
}
});