I am testing JS with OOP for using a math calculation learning site and I have got the following question with my following code:
function init() {
const mytask = new Aufgabensammlung("user");
mytask.readAufgabenartenForm();
document.getElementById('calc').addEventListener(
'click', mytask.readAufgabenartenForm
);
}
window.addEventListener("load", init);
My code is working fine. The line with “mytask.readAufgabenartenForm();” is working fine.
The function reads checkboxes from a form and write the checked boxes into an array.
readAufgabenartenForm() {
this.rechenart = document.querySelectorAll("input[name='rechenart']");
console.log(this.rechenart[0].checked);
console.log(this.rechenart[1].checked);
console.log(this.rechenart[2].checked);
console.log(this.rechenart[3].checked);
if (this.rechenart[0].checked) {
this.selektierteCheckboxen.push(1);
}
if (this.rechenart[1].checked) {
this.selektierteCheckboxen.push(2);
}
if (this.rechenart[2].checked) {
this.selektierteCheckboxen.push(3);
}
if (this.rechenart[3].checked) {
this.selektierteCheckboxen.push(4);
}
// Array Selektierte Checkboxen ausgeben
console.log(this.selektierteCheckboxen);
}
It is all working, when I am loading the site.
But when I want to click on the button with the id “calc” (see EventListener) it doesn’t work and I will get the message:
Uncaught TypeError: Cannot read properties of undefined (reading ‘push’)
at HTMLButtonElement.readAufgabenartenForm (mathquiz.js:134:34)
When you click the calc button and it runs your function, this is going to point to the calc button, not your Aufgabensammlung object as you would expect. You can fix this by not assigning the function to the click handler directly and instead using a wrapping function.
To format code, select your code and click on the </> button in the text editor menu. This will help make you code more readable and make it easier for members to assist you.
To illustrate, you can try these out and look at the console for their outputs
const test = {
func: function () {
console.log(this);
}
};
// invoked on the test object
test.func(); // outputs the test object
// the function definition 'func' e.g. just the function is assigned to myHandler
const myHandler = test.func;
myHandler(); // is not being invoked on test anymore, instead outputs the default global window object
// explicitly binding myHandler to 'test' and invoking
myHandler.bind(test)(); // the test object
The long and short of this, is that we get different results depending on where the function is being invoked. Is it being invoked on test, the window or another object.
In the case of addEventListener for convenience the handler by default is bound to the element it is attached to e.g. a button, rather than the default global window.
Note this is a bit of a rushed explanation, as I need to head out the door. May well edit this when I return.