0

I don't understand if it is possible to use class methods in another method of the same class. If so, where am I making a mistake

class Form {

    constructor (classForm, name, email, phone, text) {
        this.form = document.querySelector(`.contactForm`);
        this.name = document.querySelector(`.contactForm [name=${name}]`);
        this.email = document.querySelector(`.contactForm [name=${email}]`);
        this.phone = document.querySelector(`.contactForm [name=${phone}]`);
        this.text = document.querySelector(`.contactForm [name=${text}]`);
        this.submit = document.querySelector(`.contactForm [name=submit]`);
    }

    checkPhone () {
        return this.phone.value.length >= 12;
    }

    formSubmit (el) {
        console.log(this.checkPhone())
        el.preventDefault();
        console.log('not')
    }

}

const formContact = new Form("contactForm", "nameUser", "emailUser", "phoneUser");
formContact.form.addEventListener("submit", formContact.formSubmit);

"Uncaught TypeError: this.checkPhone is not a function"

3 Answers3

2

Basically, because in JavaScript, this reference inside functions can be bound to different objects depending on where the function is being called.

You can fix this with two techniques:

  1. Use Function.prototype.bind() to bind this when you pass a method as a callback.
class Form {
    // ...

    checkPhone () {
        return this.phone.value.length >= 12;
    }

    formSubmit (el) {
        console.log(this.checkPhone())
        el.preventDefault();
        console.log('not')
    }
}

const formContact = new Form("contactForm", "nameUser", "emailUser", "phoneUser");
formContact.form.addEventListener("submit", formContact.formSubmit.bind(formContact));
  1. Use arrow functions which have different semantics than traditional JavaScript functions.
class Form {
    // ...

    checkPhone = () => {
        return this.phone.value.length >= 12;
    };

    formSubmit = (el) => {
        console.log(this.checkPhone())
        el.preventDefault();
        console.log('not')
    };
}

const formContact = new Form("contactForm", "nameUser", "emailUser", "phoneUser");
formContact.form.addEventListener("submit", formContact.formSubmit);

I believe this question is quite common, but if you would like to understand the issue in more depth I have left some links below:


FreeCodeCamp


StackOverflow

scottwillmoore
  • 450
  • 2
  • 9
1

Yes, you can. You need to bind the formContact.formSubmit function in the event listener to the formContact: the scope of this inside of the event listener will be window if you don't bind it.

formContact.form.addEventListener("submit", formContact.formSubmit.bind(formContact));
ask4you
  • 768
  • 3
  • 14
1

You problem is that inside your formSubmit function the this value isn't what you think. A way to fix that would be to bind it to your classe's this.

You could either do that when you call the function, of you can just add it to your constructor.

Something like this:

class Form {

  constructor(classForm, name, email, phone, text) {
    this.form = document.querySelector(`.contactForm`);
    this.name = document.querySelector(`.contactForm [name=${name}]`);
    this.email = document.querySelector(`.contactForm [name=${email}]`);
    this.phone = document.querySelector(`.contactForm [name=${phone}]`);
    this.text = document.querySelector(`.contactForm [name=${text}]`);
    this.submit = document.querySelector(`.contactForm [name=submit]`);

    this.formSubmit = this.formSubmit.bind(this);
    //this.form.addEventListener('submit', this.formSubmit);
  }

  checkPhone() {
    return this.phone.value.length >= 12;
  }

  formSubmit(el) {
    console.log(this.checkPhone())
    el.preventDefault();
    console.log('not')
  }

}

const formContact = new Form("contactForm", "nameUser", "emailUser", "phoneUser", "textUser");
formContact.form.addEventListener("submit", formContact.formSubmit);
<form action="#" class="contactForm">
  <input type="text" name="nameUser" />
  <input type="email" name="emailUser" />
  <input type="text" name="phoneUser" />
  <input type="text" name="textUser" />
  <input type="submit" name="submit" value="submit" />
</form>

idea 1

You can also see at the end of the constructor i have added a extra this.form.addEventListener('submit', this.formSubmit); (which is commented out).

If you really want a class to take care of the form, then why not let the class listen to the form submit. This means you would not need to call it from outside the class.

(you could replace your formContact.form.addEventListener("submit", formContact.formSubmit); with the this.form.addEventListener('submit', this.formSubmit); inside the class constructor)

Idea 2

Something else you could try would be to change your formSubmit into an arrow function:

formSubmit = (el} => {
    ...
}

Arrow functions don't have the same this as normal function

Info

Here is some useful information about the bind on MDN

PS:

Also, you forgot the "textName" parameter on your new Form(...)

Boguz
  • 1,600
  • 1
  • 12
  • 25
  • Thanks for the explanation. I did not forget "textName", I made a test class to understand how classes work in JavaScript :) – Serhii Prudkyi Nov 08 '22 at 12:08
  • @SerhiiPrudkyi glad i could help. If you want to learn about it, i think MDN always has nice information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes – Boguz Nov 08 '22 at 13:32