Question to add an EventListener / OOP

Hello!

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)

Is there anyone who can help?

1 Like

Where have you defined “selektierteCheckboxen”?
And to use push, it needs to be an array.

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.

document.getElementById('calc').addEventListener('click', function(){
    mytask.readAufgabenartenForm();
});
2 Likes

Hi! Yes I have.

class Aufgabensammlung {
  // Attribute
  selektierteCheckboxen = new Array(); // <<<<<<!!!!!!!!!!!!
  aufgabenliste = new Array();
  rechenart = new Array();
  aktuelleAufgabe = 0;
  constructor(spielername) {
    this.name = spielername;
  }

Hi @info3289, welcome to the forum.

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.

I have done it for you this time.

Thanks.

Another option is to use Function bind.

document.getElementById('calc').addEventListener(
  'click',
  // will bind readAufgabenartenForm's 'this' to mytask
  mytask.readAufgabenartenForm.bind(mytask)
);
1 Like

Wow! Thanks a lot !!! I would never have thought of it. Do you have any sources to read the basics on this topic?

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.