Reputation: 177
all
I was trying to use insertAdjacentHTML()
to create elements and add events by using addEventListener()
.I don't think there was a logical problem in my code below, but it was not working (not console.log()ing)
My code was as below:
const END_POINT = "https://swapi.dev/api/people/"
let ul = document.querySelector("ul")
fetch(END_POINT)
.then(response => response.json())
.then(data => {
let people = data.results
console.log(people)
people.forEach((person, i) => {
let html = `
<li><a href=${person.homeworld} target="_blank">${person.name}</a></li>
`
ul.insertAdjacentHTML("afterbegin", html)
function expandDetails(ev) {
ev.preventDefault()
console.log("fef")
console.log("ev.target", ev.target)
}
let a = document.querySelectorAll("a")[i]
a.addEventListener("click", expandDetails)
})
})
<ul id="list"></ul>
I have a feeling it's about a delay of something and a setTimeout()
should be added somewhere. Any advice?
Upvotes: 0
Views: 178
Reputation: 63514
Instead of listeners on all list items use event delegation. Attach one listener to the ul
element and have that listen to events from its child elements as they "bubble up" the DOM. When expandDetails
is called check that the event is from an anchor in a list item, and then log the result.
const END_POINT = "https://swapi.dev/api/people/"
const ul = document.querySelector("ul")
ul.addEventListener('click', expandDetails);
function expandDetails(e) {
if (e.target.matches('li a')) {
e.preventDefault();
console.log(e.target.textContent);
}
}
fetch(END_POINT)
.then(response => response.json())
.then(data => {
const people = data.results;
people.forEach((person, i) => {
const html = `
<li>
<a href=${person.homeworld}>${person.name}</a>
</li>
`
ul.insertAdjacentHTML("afterbegin", html)
});
});
<ul id="list"></ul>
Another thing you might consider is creating an array of HTML and then joining
it up before adding it to the DOM. That way you're only calling insertAdjacentHTML
once after all the HTML has been compiled rather on every iteration of the loop. (Note, however, that this version prints the list items in the opposite order to the previous example which may or may not be an issue. I've also used async/await
to make the code a little neater.)
const END_POINT = "https://swapi.dev/api/people/"
const ul = document.querySelector("ul")
ul.addEventListener('click', expandDetails);
function expandDetails(e) {
if (e.target.matches('li a')) {
e.preventDefault();
console.log(e.target.textContent.trim());
}
}
async function main() {
const response = await fetch(END_POINT);
const { results } = await response.json();
const html = results.map(person => {
return `
<li>
<a href=${person.homeworld}>
${person.name}
</a>
</li>
`
});
ul.insertAdjacentHTML('beforeend', html.join(''));
}
main();
<ul id="list"></ul>
Upvotes: 1
Reputation: 5121
Just do it outside your loop:
const END_POINT = "https://swapi.dev/api/people/"
let ul = document.querySelector("ul")
fetch(END_POINT)
.then(response => response.json())
.then(data => {
let people = data.results
people.forEach((person, i) => {
let html = `
<li><a href=${person.homeworld} target="_blank">${person.name}</a></li>
`
ul.insertAdjacentHTML("afterbegin", html)
})
document.querySelectorAll("a").forEach(a => a.addEventListener('click', expandDetails))
})
function expandDetails(ev) {
ev.preventDefault()
console.log("ev.target", ev.target)
}
<ul id="list"></ul>
Upvotes: 2