Reputation:
I am using ExpressJS 4.16 on Node v8.9.4, and have created base controller that handles default routes. Here is an sample example:
class BaseController {
constructor(name, app, router, data) {
this._name = name;
this._app = app;
this._router = router;
this._data = data;
}
get name() {
return this._name;
}
setup_aggregate_routes() {
//Add Top Level Routes (All Entities)
this._router
.route(this.aggregate_route) // route = {application_root}/{entity}s/
.get(this.get_aggregate_request)
}
default_request(req, res) {
res.status(400).json(this.not_implemented_message);
}
get aggregate_route() {
return `/${this.name}s`;
}
get_aggregate_request(req, res) {
this.default_request(req, res);
}
}
The "this._router" is an "express.router()" object and the "this._app" is an express object. I then proceed to inherit from this class as so.
const BaseController = require("./base");
class CatalogController extends BaseController {
get_aggregate_request(req, res) {
console.log(this._data);
console.log(this.name);
res.status(200).json();
}
}
However, when doing this when I am in the get_aggregate_request callback for the subclass "CatalogController", "this" is undefined. I then proceed to replace "this" with "super" but the properties such as "_data" are not available and "name" getter is called but when it uses this._name it is not available.
I am stumped as to why. Any assistance to properly wire this up would be appreciated.
EDIT Here is an example of how super is being used:
const BaseController = require("./base");
class CatalogController extends BaseController {
get_aggregate_request(req, res) {
console.log(super._data);
console.log(super.name);
res.status(200).json();
}
}
Here is an example of how the class is instantiated:
const catalog_controller = new CatalogController(
"catalog",
app,
express.Router(),
data.catalog
);
** Additional information ** In order to address this problem I simplified the code and removed Express from the equation
Base Controller:
class BaseController {
constructor(
name, data
) {
this._name = name;
this._data = data;
}
get name() {
return this._name;
}
setup_aggregate_routes() {
//Add Top Level Routes (All Entities)
this.example_test_function(null, this._data, this.callback)
}
example_test_function(err, data, cb){
cb(data);
}
callback(data){
console.log(`${this.name}: ${JSON.stringify(data)}`);
}
default_request(req, res) {
res.status(400).json(this.not_implemented_message);
}
get_aggregate_request(req, res) {
this.default_request(req, res);
}
}
module.exports = BaseController;
Catalog Controller (inherited):
const BaseController = require("./base");
class CatalogController extends BaseController {
callback(data) {
console.log(`${this.name}: ${JSON.stringify(data)}`);
}
}
module.exports = CatalogController;
Driver:
const BaseController = require("./base")
const base_controller = new BaseController("base",
{ a:"abc" }
)
base_controller.setup_aggregate_routes()
const CatalogController = require("./catalog");
const catalog_controller = new CatalogController(
"catalog",
{ a:"abc" }
);
catalog_controller.setup_aggregate_routes()
Since ES2015/ES6 does not require an explicit call to the super constructor in a subclass constructor if the signatures are the same. The subclass ends up using the base (super) class constructor. So this is not an inheritance problem. I then tested the above and ran into a similar problem. It is not a problem with Inheritance or Express. It is the old javascript context problem and using "this".
This is identified here. How to access the correct `this` inside a callback?
Based on the last identified sample, if I change the code based on one of the identified solutions:
from:
cb(data);
to:
cb.bind(this)(data);
It works. I will provide a complete solution using ExpressJS as well
Upvotes: 1
Views: 237
Reputation:
The solution to this problem is associated to context, callbacks and the use of "this" and not an inheritance problem nor Express problem. It is identified here:
How to access the correct `this` inside a callback?
If I was using my original example to correct this problem, the only change I would need to apply is the following:
Change this:
.get(this.get_aggregate_request)
To this:
.get(this.get_aggregate_request.bind(this))
Of course there are other ways to resolve the context problem as identified in the article but that is ultimately up to you.
Upvotes: 1
Reputation: 10111
try this
class CatalogController extends BaseController {
constructor(name, app, router, data) {
super(name, app, router, data);
}
get_aggregate_request(req, res) {
//super(req, res); // if you want to call
res.status(200).json();
}
}
Upvotes: 0