It is not possible to call a method in the class that it defined in ES6 in Node.js

I am building an application using Node.js, Express.js and MongoDB. I use the MVC pattern and also have a separate file for routes. I am trying to create a Controller class in which a method calls another method declared inside it. But I can’t do it. I get "Can't read the" undefined "property.

index.js file

let express = require('express'); let app = express(); let productController = require('../controllers/ProductController'); app.post('/product', productController.create); http.createServer(app).listen('3000'); 

ProductController.js File

 class ProductController { constructor(){} create(){ console.log('Checking if the following logs:'); this.callme(); } callme(){ console.log('yes'); } } module.exports = new ProductController(); 

When I ran this, I get the following error message:

 Cannot read property 'callme' of undefined 

I myself ran this code with slight modifications as shown below and it works.

 class ProductController { constructor(){} create(){ console.log('Checking if the following logs:'); this.callme(); } callme(){ console.log('yes'); } } let product = new ProductController(); product.create(); 

Why does one work and not the other? HELP!

+6
source share
2 answers

Your method bounces to the Layer class inside express , losing the original context. The way that access to routes is expressed is to wrap each of them in the Layer class, which assigns a route callback to itself:

 this.handle = fn; 

This is where your problems arise, this task automatically re-sets the function context to Layer . Here is a simple example demonstrating the problem:

 function Example() { this.message = "I have my own scope"; } Example.prototype.logThis = function() { console.log(this); } function ReassignedScope(logThisFn) { this.message = "This is my scope now"; // simulation of what is happening within Express Layer this.logThis = logThisFn; } let example = new Example() let scopeProblem = new ReassignedScope(example.logThis); scopeProblem.logThis(); // This is my scope now 

Others have already indicated a solution that should explicitly bind your method to an instance of ProductController :

 app.post('/product', productController.create.bind(productController)); 
+2
source

When you pass the create method as a method, it is probably called in a different context ( this ), as you would expect. You can link it:

 app.post('/product', productController.create.bind(productController)); 

There are many other ways to ensure that this refers to the correct object.

eg. wrap it with a function (arrow or classic):

 app.post('/product', (...args) => productController.create(...args)); 

Or binding methods in the constructor:

 constructor() { this.create = this.create.bind(this); } 
+2
source

All Articles