-2

I have a class, and another class that extends the fist one. In my code I create a new instance of the extended class: new MyCustomEndpoint(router);

the problem is that handleIsNotOk is undefined in initMyRoutes

export class MyEndpoint {
    constructor(router: express.Router) {
        this.initMyRoutes(router); 
    }

    protected initMyRoutes(router: express.Router) {
        router.get(`/v1/isok`, this.handleIsOk);
    }

    protected handleIsOk = (req: express.Request, res: express.Response) => {
        res.send(200);
    }
}


export class MyCustomEndpoint extends MyEndpoint{
    private test = "Test";

    protected initMyRoutes(router: express.Router) {
        console.log(this.handleIsNotOk); // undefined
        console.log(this.handleIsNotOkFn);

        router.get(`/v1/isokcustom`, this.handleOk); // this works
        router.get(`/v1/isnotok`,this.handleIsNotOk); // this doesn't works
        router.get(`/v1/isnotokfn`, this.handleIsNotOkFn); // this doesn't works
        router.get(`/v1/isnotokfn`, (req, res)this.handleIsNotOkFn(req,res)); // works but it's ugly since it's different compared to router.get(`/v1/isokcustom`, this.handleOk);
    }

    protected handleIsNotOk = (req: express.Request, res: express.Response) => {
        res.send(200);
    }

    protected handleIsNotOkFn(req: express.Request, res: express.Response){
        console.log(this.test); // undefined
        res.send(200);
    }
}

...

new MyCustomEndpoint(router);

why is this happening? should not be undefined in my opinion

Zerotwelve
  • 2,087
  • 1
  • 9
  • 24
  • 1
    Most likely: [How to access the correct `this` inside a callback](https://stackoverflow.com/q/20279484) I suspect `initMyRoutes` is passed as a method reference (e.g. `somethingThatTakesCallback(this.initMyRoutes)`), which will always lose the value of `this` when it gets executed. – VLAZ Jun 09 '22 at 08:41
  • yes, but what would be your suggested solution? I know I can do it like this: `router.get(`/v1/isnotokfn`, this._chatPermissionSecurity.readAccessMiddleware, (req,res) => this.handleIsNotOkFn(req,res));` but I don't like it since it's a different approach than in `MyEndpoint` – Zerotwelve Jun 09 '22 at 08:49
  • `protected function handleIsNotOkFn() {...}` is not a syntactically valid class member – Aluan Haddad Jun 09 '22 at 08:53
  • @AluanHaddad why not? as described in my comment above, it actually works (but I don't like it) – Zerotwelve Jun 09 '22 at 08:57
  • Sorry but it's not. What do you think it means? – Aluan Haddad Jun 09 '22 at 09:01
  • @AluanHaddad yeah it should be `protected handleIsNotOkFn(req: express.Request, res: express.Response){}` (copy paste error). But would be nice if you help to find an answer ;) – Zerotwelve Jun 09 '22 at 09:08

3 Answers3

1

I bet this is the reason

router.get(`/v1/isnotokfn`, this.handleIsNotOkFn); 

and if you bind it to the instance, it'll work just fine:

router.get(`/v1/isnotokfn`, this.handleIsNotOkFn.bind(this)); 
mbojko
  • 13,503
  • 1
  • 16
  • 26
  • thanks, this works, same as `(req,res) => this.handleIsNotOkFn(req,res));` but it's kinda of ugly since it's not the same syntax as in `MyEndpoint` but probably the only solution – Zerotwelve Jun 09 '22 at 09:16
  • @Zerotwelve An arrow function will loose any concept of a class, so yes, you will need to use bind. Or avoid class altogether and just use functional coding, personally I find that less ugly.. – Keith Jun 09 '22 at 09:18
  • @Keith the arrow function in `MyEndpoint` `handleIsOk` works fine and I have reference on `this`, the same exact code in `MyCustomEndpoint` doesn't work probably because `this` references the super Class – Zerotwelve Jun 09 '22 at 09:22
  • @Zerotwelve Have you come on SO for help, or just constantly contradict everything people say. If so, you will find nobody will want to help you. An arrow function has no concept of a class, it has no `this`. Your `handleIsOk` works now, only because there is no reference to the class, soon as you want that your up the creek without a paddle. – Keith Jun 09 '22 at 09:24
  • @Keith I am not trying to contradict everyone, actually I upvoted this answer. I am looking for a suitable solution to my use case – Zerotwelve Jun 09 '22 at 09:28
  • Actually, arrow functions _don't_ lose the context, they use lexical `this`. It's the `function` functions that don't behave and require putting more thought into the "what is _this_?" question. Inheritance complicates things even more. – mbojko Jun 09 '22 at 09:36
  • @mbojko Yes, wording slightly wrong, but I was on about were the OP was attaching an arrow function to a class, `this` will be `undefined`.. As the context then will be nothing.. – Keith Jun 09 '22 at 09:41
  • 1
    @Zerotwelve If you want to avoid bind, ironically an arrow function is what this was designed for, but you need to be using it at the caller end, not the class. eg. `router.get('/v1/isnotokfn', () => this.handleIsNotOkFn());`, Is this less ugly than bind, that's something only you can decide. – Keith Jun 09 '22 at 09:47
0

You overwrite initMyRoutes and you're waiting your mother class to call the new initMyRoutes. You should have a constructor in MyCustomEndPoint where you call initMyRoutes. MyCustomEndPoint never calls initMyRoutes

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
Main
  • 3
  • 1
0

Self Answer

Thanks to @mbojko @Keith @VLAZ and everyone else for the answers.

Even if technically correct, the solutions didn't fit my needs. My use-case is kinda peculiar and there is a reason why I am doing it like this.

FYI: This is the solution that fits my needs

export class MyCustomEndpoint extends MyEndpoint{

    constructor(router: express.Router) {
        super(router);
        this.initCustomRoutes(router);
    }

    // will be called in the constructor of the super class
    protected initMyRoutes(router: express.Router) {
        router.get(`/v1/isokcustom`, this.handleOk); 
    }

    private initCustomRoutes(router: express.Router) {
        router.get(`/v1/isokcustom`, this.handleOkCustom); 
    }

    protected handleOkCustom = (req: express.Request, res: express.Response) => {
        res.send(200);
    }

}
Zerotwelve
  • 2,087
  • 1
  • 9
  • 24