I have fetched some data from a URL and after that I have generated an HTML template for each item of received data using a forEach
loop. After creating the HTML template for all the elements in response data I have assigned that to document.body.innerHTML
. So it displays all elements with my HTML template.
The response has 30 objects and each object has a link (clone_url
) with other information. I have generated HTML elements for those 30 objects using my HTML template, each has a name, profile Avatar and button to copy the specific link I have mentioned. I want to copy that link into the clipboard when user click the copy button.
Therefore, I want to add event listeners to the buttons. That is where I have been struggling because I have no idea how can I do that. Because I have to access each component and also I want to access related response object to get the link.
const url = "https://api.github.com/users/shrutikapoor08/repos";
fetch(url)
.then((response) => response.json())
.then((users) => {
console.log(users);
let htmlText = "";
users.forEach((i) => {
htmlText += `
<div class="repo-container">
<p class="repo-title">${i.name}</p>
<div class="repo-owner">
<img
src="${i.owner.avatar_url}"
alt="avatar"
class="avatar"
/>
<a href="${i.owner.html_url}" class="repo-owner-username">${i.owner.login}</a>
</div>
<div class="link-container">
<button class="repo-link-btn">Copy</button>
<p class="tooltip">Link Coppied</p>
</div>
</div>
`;
});
document.body.innerHTML = htmlText;
});
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Roboto", sans-serif;
}
.repo-container {
background-color: rgb(255, 253, 251);
border: 1px solid rgb(226, 226, 226);
padding: 15px;
width: 250px;
margin: 10px;
}
.repo-title {
font-weight: bold;
margin-bottom: 10px;
}
.repo-owner {
display: flex;
align-items: center;
}
.avatar {
width: 30px;
height: 30px;
border-radius: 50%;
margin-right: 20px;
}
.repo-owner-username {
font-size: 0.8rem;
text-decoration: none;
}
.tooltip {
background-color: rgba(0, 0, 0, 0.7);
width: fit-content;
padding: 4px 10px;
border-radius: 10px;
font-size: 0.75rem;
color: white;
opacity: 0;
transition: transform 0.3s ease, opacity 0.3s ease;
pointer-events: none;
}
.tooltip.active {
opacity: 1;
transform: translateY(-10px);
}
.link-container {
display: flex;
}
.repo-link-btn {
margin: 10px 0px;
}
<!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" />
<link rel="stylesheet" href="./style.css" />
<title>Document</title>
</head>
<body>
<script src="./app.js"></script>
</body>
</html>
This is the code I want to add with each button.
document.querySelector(".repo-link-btn").addEventListener("click", async () => {
const text = "";
await navigator.clipboard.writeText(text);
document.querySelector(".tooltip").classList.add("active");
setTimeout(() => {
document.querySelector(".tooltip").classList.remove("active");
}, 500);
});
const text
should be equal to the response data objects URL. I have to access that data as well. What is the good practice for solving this problem?
If you want to use pure JavaScript you need to create loop and add event listener to all item like this:
[...document.querySelectorAll(".repo-link-btn")].forEach(function (item) {..}
And to find clone_url
value you can set custom attribute like data-cloneUrl="${i.clone_url}"
and then get it in click time: e.target.getAttribute("data-cloneUrl");
Note that this code is based on your html and pure JavaScript. There is more easy way by jQuery.
const url = "https://api.github.com/users/shrutikapoor08/repos";
fetch(url)
.then((response) => response.json())
.then((users) => {
console.log(users);
let htmlText = "";
users.forEach((i) => {
htmlText += `
<div class="repo-container">
<p class="repo-title">${i.name}</p>
<div class="repo-owner">
<img
src="${i.owner.avatar_url}"
alt="avatar"
class="avatar"
/>
<a href="${i.owner.html_url}" class="repo-owner-username">${i.owner.login}</a>
</div>
<div class="link-container">
<button class="repo-link-btn" data-cloneUrl="${i.clone_url}">Copy</button>
<p class="tooltip">Link Coppied</p>
</div>
</div>
`;
});
document.body.innerHTML = htmlText;
[...document.querySelectorAll(".repo-link-btn")].forEach(function (item) {
item.addEventListener("click", async (e) => {
const text = e.target.getAttribute("data-cloneUrl");
await navigator.clipboard.writeText(text);
document.querySelector(".tooltip").classList.add("active");
setTimeout(() => {
document.querySelector(".tooltip").classList.remove("active");
}, 500);
});
})
});
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Roboto", sans-serif;
}
.repo-container {
background-color: rgb(255, 253, 251);
border: 1px solid rgb(226, 226, 226);
padding: 15px;
width: 250px;
margin: 10px;
}
.repo-title {
font-weight: bold;
margin-bottom: 10px;
}
.repo-owner {
display: flex;
align-items: center;
}
.avatar {
width: 30px;
height: 30px;
border-radius: 50%;
margin-right: 20px;
}
.repo-owner-username {
font-size: 0.8rem;
text-decoration: none;
}
.tooltip {
background-color: rgba(0, 0, 0, 0.7);
width: fit-content;
padding: 4px 10px;
border-radius: 10px;
font-size: 0.75rem;
color: white;
opacity: 0;
transition: transform 0.3s ease, opacity 0.3s ease;
pointer-events: none;
}
.tooltip.active {
opacity: 1;
transform: translateY(-10px);
}
.link-container {
display: flex;
}
.repo-link-btn {
margin: 10px 0px;
}
Note that the snippet worked correctly But stack overflow snippet said The Clipboard API has been blocked because of a permissions policy applied to the current document
. So check the snippet in your computer.