I want to add the click event to a created Element dynamically that when user click on button create some elements (elements that show in code below) and when user click on element named remov must run function named deltion BUT that doesnt work.How can I implemented that ?
I use Vue js
methods: {
showinfo: function() {
db.collection("Studnets")
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
const student = document.createElement("tr");
const email = document.createElement("td");
email.innerText = doc.data().email;
const name = document.createElement("td");
name.innerText = doc.data().name;
const phone = document.createElement("td");
phone.innerText = doc.data().phone;
const stage = document.createElement("td");
stage.innerText = doc.data().stage;
const remov = document.createElement("button");
const pic = document.createElement("img");
pic.setAttribute("src","/dist/delete.svg?afdf9975229cdc15458e851b478bb6cb");
remov.classList.add("del");
//the problem
remov.addEventListener("click", this.deltion());
student.appendChild(email);
student.appendChild(name);
student.appendChild(phone);
student.appendChild(stage);
student.appendChild(remov);
remov.appendChild(pic);
document.getElementById("studentList").appendChild(student);
},
deltion: function(e) {
const rawStudent = e.target;
const raw = rawStudent.parentElement;
console.log(raw);
raw.remove();
}
There are three issues with your code.
First Issue: invoking a function on the event listener
you are calling the deltion (maybe you mean deletion :P) function when you register the event listener.
remov.addEventListener("click", this.deltion());
the correct form is
remov.addEventListener("click", this.deltion);
Because you want to pass the function body to the event listener, not the function result. (you can wrap the function in an arrow function if you want to call it, but at the end is the same).
Second Issue: this is not this
If you fix the first one, you'll find another one (the life of programmers). this is a special keyword in js, the context of this will change depending on the caller.
**this**
keyword context changes.**this**
keyword context is changed again.A solution will be to use arrow functions so this don't get bonded to the parent function.
db.collection("Studnets").get().then(querySnapshot => {
querySnapshot.data.forEach(doc => {
// code
})
})
If for some reason you can't use arrow functions, you can add a variable that "shadows" the context of the this
keyword on the showinfo function.
showinfo() {
const vm = this;
api.getStudentsCollection().then(function(querySnapshot) {
querySnapshot.data.forEach(function(doc) {
// setup code
remov.addEventListener("click", vm.deltion);
// setup code
});
});
}
Third Issue: clicking the arrow image will delete the button but not the tr Use currentTarget instead of the target, the target is the element the user click, it can be any element inside the button like the image, currentTarget is the element that the event listener is attached aka the button.
{
deltion: function(e) {
const rawStudent = e.currentTarget;
const raw = rawStudent.parentElement;
console.log(raw);
raw.remove();
}
}
Unsolicited Advice
Vue excels with its simplicity and declarative code. You can solve the problem like your original code, but there is a simpler way to let the component manage its state.
I replicated your code with the original version fixed and the simplest vue way (with a simple empty and loading state toggle). Hope you find it useful and learn from this. :) https://codesandbox.io/s/student-list-ammar-yasir-b5sxo?file=/src/App.vue
Learning references