I've been working on a to do list for my web dev studies with The Odin Project. My assignment is to create a to-do app and I chose the composite design pattern to do after a lot of struggle with my previous messy code. So far so good but one of my button oddly doesn't trigger the arrow function I prepared for it. I said oddly cause I've got a very similar approach for another button the works perfectly. The only difference I feel it's causing this issue is an assignment to a button for the let's call it root of this tree structure (session.js class). document.getElementById effectively finds the specific button in the document and the addEventListener trigger a alert for example if there's no arrow function involved. Can anyone lend me a hand with this please?
The problem is in the addEventListener inside the if statement inside the addChild function of the following class
import Component from './component.js';
export default class Container extends Component{
child;
constructor(){
super();
}
addChild(id, parentId){
alert(id);
alert(parentId);
document.getElementById(parentId).appendChild(document.createElement('div'));
document.getElementById(parentId).lastChild.id = id;
document.getElementById(parentId).lastChild.innerHTML = this.child.innerHTML;
document.getElementById(parentId).lastChild.className = this.child.className;
if(document.getElementById(id).className!='check-list'){
document.getElementById(id).innerHTML ="<button id='" id "-add-button'></button>";
document.getElementById(id '-add-button').addEventListener('click', ()=>{
this.child.addChild(this.parentNode.id);
});
}
document.getElementById(id).innerHTML ="<button id='" id "-remove-button'></button>";
document.getElementById(id '-remove-button').addEventListener('click', ()=>{
document.getElementById(id).parentNode.removeChild(document.getElementById(id));
});
let inputs = document.getElementById(parentId).getElementsByClassName('input');
for(let i=0; i<inputs.length; i){
inputs[i].addEventListener('input', ()=>{
inputs[i].dataset.storage = inputs[i].value;});
}
}
}
Container class inherits from Component class
export default class Component{
className;
innerHTML;
constructor(){
}
}
And Session class is the only class that, if I can call it override in this case the same event
import Project from "./project.js";
import Container from "./container.js";
export default class Session extends Container{
constructor(username){
super();
this.username = username;
this.child = new Project();
this.innerHTML = ["<div id='" this.username "-session' class='session' data-checklist='' data-card='' data-list='' data-project''>",
"<H1>Call it a day!</H1>",
"<button id='session-add-button'>Add Project</button>",
"<button id='logout'>Log out</button>",
"</div>"].join("");
document.body.innerHTML = this.innerHTML;
document.getElementById('session-add-button').addEventListener('click', ()=>{
this.addChild(this.username "-session");
})
}
addChild(parentId){
super.addChild(Project.getId(), parentId);
Project.count;
}
}
BTW Project class is Session class child so you guys can picture the whole flow in your minds
import Container from "./container";
import List from "./list";
export default class Project extends Container {
static count=0;
static getId(){
return 'P-' Project.count;
}
constructor(){
super();
this.child = new List();
this.className = 'project';
this.innerHTML = ["<input class='input' data-storage='' type='text' placeholder='Project title'></input>"].join("");
}
addChild(parentId){
super.addChild(List.getId(), parentId);
List.count;
}
}
I've checked already if the button inside that if in the container.js script is found as well as declare a function without the arrow function. I've also tried to find the difference between this add button that has issues with the remove button and I can't see anything that I'm doing wrong in terms of typing or syntax.
CodePudding user response:
You could use something like addEventListener('click', (event) => {});
and then inside that reference the event
properties like target
re:
https://developer.mozilla.org/en-US/docs/Web/API/Event/target
Super simple example: where now you DO have this
as well
// Make a list
const ul = document.createElement('ul');
document.body.appendChild(ul);
const li1 = document.createElement('li');
const li2 = document.createElement('li');
const btn = document.createElement('button');
btn.textContent = "Howdy Click me, I am not the li here but the UL triggers";
li2.appendChild(btn);
ul.appendChild(li1);
ul.appendChild(li2);
function hitMe(event) {
// event.target refers to the clicked <li> element
// This is different than event.currentTarget, which would refer to the parent <ul> in this context
event.target.classList.toggle('blue-sky');
event.currentTarget.classList.toggle("red-sky");
console.log(this);
console.log("target?:",this == event.target);
console.log("currentTarget:?",this == event.currentTarget);
}
// Attach the listener to the list
// It will fire when each <li> is clicked
ul.addEventListener('click', hitMe, false);
ul {
border: solid 1px green;
}
li {
border: solid 3px orange;
}
.blue-sky {
border-color: skyblue;
}
.red-sky {
background-color: #ffdddd;
border-width: 4px;
padding: 1em;
}
CodePudding user response:
Arrow functions don't have their own bindings to this
as methods, so this
in your function refers to the window
document.getElementById('session-add-button').addEventListener('click', ()=>{
this.addChild(this.username "-session"); // `this` refers to `Window`
})
To fix just use an anonymous function, e.g.
var username = this.username;
document.getElementById('session-add-button').addEventListener('click', function() {
this.addChild(username "-session"); // `this` refers to your button
})
Your other use of the arrow function works because you don't reference this
in it.