2

I'm developing a simple API in node with pure javascript classes. I'm declaring all my routes in a single file then another one just for the controllers logic.

routes.js

const express = require('express');
const router = express.Router();

const MyController = require('../controllers/my.controller');
const myController = new MyController();


router.post('/', myController.test);

module.exports = router;

MyController.js

class MyController {

    constructor() {
        this.valueA = 10;
        this.valueB = 30;
    }

    test() {
        // some logic
        // but values from constructor always undefined
        return this.valueA;
    }
    ...
}


module.exports = MyController;

but when I tried to call this route on my localhost, I always get:

TypeError: Cannot read property 'valueA' of undefined

If this class is always initialized when call the routes file, couldn't I get the values from the constructor?

5
  • 2
    You may need to bind the context to your method: router.post('/', myController.test.bind(myController)); Commented Jul 4, 2020 at 23:12
  • also note that your post handling function is, at the least, missing req and res arguments. It still needs to obey the express middleware signature. Commented Jul 4, 2020 at 23:14
  • @Mike'Pomax'Kamermans That's not required. Express passes these to the function, but the function itself is free to use them or not ;) JS is loose, after all Commented Jul 4, 2020 at 23:15
  • I know, but if you don't intend to work with them, wth are you doing using Express? Either you form a response on res or you do your work and call next(). If that's not your intention, you have no reason to use express.js at all. That's the whole reason you use express. Middleware chaining. Commented Jul 4, 2020 at 23:20
  • its not a "real" implementation. I just use that to demonstraste the problem more clear. that's why I didn't declare req and res Commented Jul 4, 2020 at 23:22

2 Answers 2

4

Your class is constructed as you expected. However, the method is called without context (the this) because you pass the method as the route handler. You need to bind the this and there are several ways to do it.

wrap the method with a function

router.post('/', function(...args) {
  return myController.test(...args)
});

or using the arrow function

router.post('/', (...args) => myController.test(...args));

Function#bind

router.post('/', myController.test.bind(myController));

Define the method with the arrow function

This requires you to use Babel to handle.

class MyController {
    ....
    test = () => {
        // some logic
        // but values from constructor always undefined
        return this.valueA;
    }
    ...
}
Sign up to request clarification or add additional context in comments.

2 Comments

thanks it worked. but it's a bad or good practice what i'm doing?
glad you found it helpful! I think it's a very common approach.
0

if the class method test() isn't returning anything then add return this at the end of the block like so `test(){

your code logic here

return this }and always remember to use the variable like sothis.variableName` within the block

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.