0

I have a Controller with two functions, and one calls the other using this, But when a call it the this is undefined

I've tried to follow these instructions when I make an exemple it works, but when I implement it in my code the this stills undefined.

Controller:

import AutenticacaoDAO from '../daos/autenticacao.dao'
import MailController from './email.controller'
import jwt from 'jsonwebtoken'
import TokenSecret from '../config/token-secret'
import crypto from 'crypto'
import { Request, Response } from 'express'
import { Usuario } from '../models/usuario.model';

class AutenticacaoController {
    constructor() {

    }

    public async login(req: Request, res: Response) {
        let usuario;
        try {
            usuario = await AutenticacaoDAO.login(req.body.email)
            this.tratarResposta(await crypto.createHash("md5").update(req.body.senha).digest("hex"), usuario) //THIS IS UNDEFINED HERE                     
    } catch (error) {
        res.json(error)
    }
}

tratarResposta (senhaEnviada: string, usuario: any) {
  // HERE I TREAT IF THE RETURNED USER IS BLOQUED OR NAH, IF THE PASSWORD 
  //IS CORRECT AND SOME OTHER STUFF
}

}

export default new AutenticacaoController()

I'm able to do my stuff inside de try statement(it works, i've tried), but the login function will be too big...

route where I call the login method:

import { Router } from 'express'
import AutenticacaoController from '../controllers/autenticacao.controller'


const AutenticacaoRoutes = Router()

AutenticacaoRoutes.post('/autenticacao/signup', AutenticacaoController.signUp)
AutenticacaoRoutes.post('/autenticacao/login', AutenticacaoController.login)
AutenticacaoRoutes.put('/autenticacao/esquecisenha/', AutenticacaoController.forgotPassword)
AutenticacaoRoutes.get('/autenticacao/recoverypassword/', AutenticacaoController.recoveryPassword)


export default AutenticacaoRoutes
  • where are you passing `login`? – Daniel A. White Jun 14 '19 at 19:55
  • You need to capture `this`, that can be done using an arrow function assignment. `login = async (req: Request, res: Response) => { /* your method body here*/}` – Igor Jun 14 '19 at 19:56
  • 1
    This may help: https://stackoverflow.com/questions/36489579/this-within-es6-class-method – Christoph Lütjen Jun 14 '19 at 19:58
  • @DanielA.White, I'm calling it from my route. – Tiago Silveira Jun 14 '19 at 20:01
  • @Igor, I was trying to make this way on `tratarResposta` function. I will try it on login. – Tiago Silveira Jun 14 '19 at 20:02
  • 1
    The problem is not in your controller, but where `login` is used. Share the controller line. You probably just need to call the `bind()` function or use an arrow function when defining the route. – Evert Jun 14 '19 at 20:43
  • @Evert, I edited the question with the route that I call the login method – Tiago Silveira Jun 14 '19 at 20:57
  • @TiagoSilveira you're running into a really common issue people run into with javascript, passing a function by reference loses its reference to this. Look up `this binding` on SO and you'll likely get to the answer. The answer will probably involve using the `bind()` function. – Evert Jun 14 '19 at 21:09
  • [Don't default-export a `new` `class` instance](https://stackoverflow.com/a/38741262/1048572) – Bergi Jun 14 '19 at 21:37

1 Answers1

0

When passing down a function as a parameter (here would be your are passing .login function as a middleware for your route) your this that you use inside that function doesn't represent your controller anymore. You need to specify what the this value is when that function will be called. To do that, you use the Function.prototype.bind(value) method.

So that means you need to change

AutenticacaoRoutes.post('/autenticacao/login', AutenticacaoController.login)

to

AutenticacaoRoutes.post('/autenticacao/login', AutenticacaoController.login.bind(AutenticacaoController))

Here's a great reference to learn about the bind method.

muchwow
  • 715
  • 7
  • 22
  • I resolved it changing the function to `public login = async (req: Request, res: Response) => { let usuario; try { usuario = await AutenticacaoDAO.login(req.body.email) this.tratarResposta(await crypto.createHash("md5").update(req.body.senha).digest("hex"), usuario) //THIS IS UNDEFINED HERE } catch (error) { res.json(error) }` I will try to resolve it using your way, it looks better. – Tiago Silveira Jun 17 '19 at 15:20