Reputation: 157
I have a nested <i>
tag that shows liked or unliked heart. The problem is that every time a post is liked it sends around 16 requests (event fires 16 times). I have tried using sleep
, and seTimeout
to no avail. I need to dynamically add the event listener to the <i>
tag.
initial_html
{% if user in post.get_likers%}
<p class="my-0 text-muted"><i style="color: red;" class="fas fa-heart hover"></i> {{post.total_likes}}</p>
{% else %}
<p class="my-0 text-muted"><i class="far fa-heart hover"></i> {{post.total_likes}}</p>
{% endif %}
Attempt to update likes per view
document.addEventListener("DOMContentLoaded", () => {
load_clickable();
});
function load_clickable() {
document.querySelectorAll("i").forEach((item) => {
item.addEventListener("click", () => {
update_likes(item);
});
});
}
function update_likes(item) {
const p_tag = item.parentNode;
const post_id = p_tag.parentNode.id;
console.log(post_id, p_tag.innerText);
const fetch_url = `/like/${post_id}`;
fetch(fetch_url, {
method: "POST",
})
.then((response) => response.json())
.then((result) => {
if (result.like) {
console.log("Has Liked");
var new_likes = parseInt(p_tag.innerText) + 1;
p_tag.innerHTML = `<i style="color: red;" class="fas fa-heart hover"></i> ${new_likes}`;
} else if (result.unlike) {
console.log("Has unliked");
var new_likes = parseInt(p_tag.innerText) - 1;
p_tag.innerHTML = `<i class="far fa-heart hover"></i> ${new_likes}`;
}
load_clickable();
});
}
How can I make it such that each event fires once?
Upvotes: 2
Views: 214
Reputation: 47
calling the load_clickable method is the problem, the click event is technically still active, why not just load the onclick
attr to the new i tag, like so
.then((result) => {
if (result.like) {
console.log("Has Liked");
var new_likes = parseInt(p_tag.innerText) + 1;
p_tag.innerHTML = `<i style="color: red;" class="fas fa-heart hover" onclick=update_likes(this)></i> ${new_likes}`;
} else if (result.unlike) {
console.log("Has unliked");
var new_likes = parseInt(p_tag.innerText) - 1;
p_tag.innerHTML = `<i class="far fa-heart hover" onclick=update_likes(this)></i> ${new_likes}`;
}
});
best solution
{% if user in post.get_likers%}
<p class="my-0 text-muted"><i style="color: red;" class="fas fa-heart hover onclick=update_likes()"></i> <span>{{post.total_likes}}</span></p>
{% else %}
<p class="my-0 text-muted"><i class="far fa-heart hover onclick=update_likes()"></i> <span>{{post.total_likes}}</span></p>
{% endif %}
then javascript
document.addEventListener("DOMContentLoaded", () => {
//do something else with loaded DOM
});
function update_likes() {
const p_tag = this.parentNode;
const post_id = p_tag.parentNode.id;
console.log(post_id, p_tag.innerText);
const fetch_url = `/like/${post_id}`;
fetch(fetch_url, {
method: "POST",
})
.then((response) => response.json())
.then((result) => {
if (result.like) {
console.log("Has Liked");
var new_likes = parseInt(p_tag.innerText) + 1;
p_tag.innerHTML = `<i style="color: red;" class="fas fa-heart hover" onclick=update_likes(this)></i> ${new_likes}`;
} else if (result.unlike) {
console.log("Has unliked");
var new_likes = parseInt(p_tag.innerText) - 1;
p_tag.innerHTML = `<i class="far fa-heart hover" onclick=update_likes(this)></i> ${new_likes}`;
}
});
}
this way all tags are already rendered with their tags
Upvotes: 1
Reputation: 89264
The issue is that you are calling load_clickable
after updating the likes, which adds event listeners to all of the <i>
elements again. Instead, you should display the amount of likes inside a <span>
and update the textContent
each time so that you do not need to attach all the event listeners again.
Updated HTML:
{% if user in post.get_likers%}
<p class="my-0 text-muted"><i style="color: red;" class="fas fa-heart hover"></i> <span>{{post.total_likes}}</span></p>
{% else %}
<p class="my-0 text-muted"><i class="far fa-heart hover"></i> <span>{{post.total_likes}}</span></p>
{% endif %}
Updated JavaScript (with parts omitted for brevity):
//...
.then((result) => {
if (result.like) {
console.log("Has Liked");
var new_likes = parseInt(p_tag.innerText) + 1;
p_tag.querySelector('span').textContent = new_likes;
} else if (result.unlike) {
console.log("Has unliked");
var new_likes = parseInt(p_tag.innerText) - 1;
p_tag.querySelector('span').textContent = new_likes;
}
});
//...
Upvotes: 2