1

I am trying to write a module that creates generic handlers for express routes

e.g.

//create a new route handler with some config
//every routeHanlder method needs to be able to access this config
var handler = new routeHandler({config: "value"});

//handle a get route ("Example 1")
app.get('route', handler.read)

//handle a get route with params ("Example 2")
app.get('route.:id', function(req, res){
    handler.read(req,res,{query: {_id: req.params.id}});
});

I am having trouble making "example 1" work...

app.get('route', handler.read)

...as I loose the value of 'this' inside handler.read

I understand why the value of 'this' is different, but I can't figure out how to make it work, or another way to get the desired results without using 'this'.

Here is a plunker link

To summarise I am trying to find a way to make my routeHandler objects (see plunker above, and code paste below) work when used as the callback of an express route (see "example 1" above).

var routeHandler = function(config){

  if (!(this instanceof(routeHandler))) {
      return new routeHandler(config);
  }

    config = config || {};

    if(config.configData){

      this.configData = config.configData;

    }

};

routeHandler.prototype = {
  read: function(req, res, options){

    //The problem: accessing configData without using this
    console.log("inside callback", this, this.configData);

    options = options || {};

  }
};

Edit: I would like the ability to create multiple instances of the route handler with different config data e.g.

var handlerOne = new RouteHandler("configDataOne"); 
var handlerTwo = new RouteHandler("configDataTwo"); 

app.get('/firstRoute', handlerOne.read); 
app.get('/secondRoute', handlerTwo.read);
PaulParton
  • 1,013
  • 1
  • 11
  • 19
  • possible duplicate of [Preserving a reference to "this" in JavaScript prototype functions](http://stackoverflow.com/questions/2025789/preserving-a-reference-to-this-in-javascript-prototype-functions) – Scimonster Nov 17 '14 at 11:05
  • Hi Scimonster, I hope I am not being really thick but I did look at that answer already. I don't see how I can use any of the examples there in my situation. – PaulParton Nov 17 '14 at 11:15
  • You can try: `app.get('route', function(){handler.read()})`. – RobG Nov 17 '14 at 11:21
  • Hi RobG, that is the method that does currently work for me (see "Example 2" in the question) – PaulParton Nov 17 '14 at 11:29
  • 2
    You can also use: `app.get('route', handler.read.bind(handler));`.. – thriqon Nov 17 '14 at 11:35
  • ooh nice one thriqon, i didn't realise that I could use bind like that. I'll work at it a little bit more because I would love to find a solution that let me use the exact code I put in "Example 1", but if I can't then I will probably go with your suggestion. (if you make that an answer I will up vote it, and mark it as correct if I end up using it) – PaulParton Nov 17 '14 at 11:44
  • 1
    You can also use something along the lines of `this.read = (function read(...) { ... }).bind(this);` inside the `routeHandler` constructor function, which will make it unnecessary to bind to the handler for each callback, and only create a new function for each instance – just like `.bind` also does. – yerforkferchips Nov 17 '14 at 12:02
  • winner winner chicken dinner! thanks yerforkferchips. That ticks everything that I need, if you make it an answer I will mark it correct and add you to my Will =) – PaulParton Nov 17 '14 at 12:06

2 Answers2

0

You can save routeHandler's configData in express object "app" like below:

app.set("routeHandlerConfigData", "identifier or whatever value you want to store");

then make your routeHandler a simple middleware

var routeHandler = function(req, res, next){
  var configData = req.app.get("routeHandlerConfigData");
  //Do whatever you want
};
  • Thanks for the answer, I hadn't considered anything like this. The only problem I can see with this approach is that I couldn't have multiple instances of the router handler with different "routeHandlerConfigData" for each. e.g. `var handlerOne = new RouteHandler("configDataOne");` `var handlerTwo = new RouteHandler("configDataTwo");` `app.get('/firstRoute', handlerOne.read); app.get('/secondRoute', handlerTwo.read);` – PaulParton Nov 17 '14 at 11:49
0

I was inspired by a great comment form yerforkferchips who suggested adding my routerHandler functions inside the constructor like this

this.read = (function read(...) { ... }).bind(this);

Which lets me do exactly what I wanted in my question

app.get('route', handler.read);

BUT i realised that I could use closures in my prototype functions which would sort my 'this' problem and that I would also be able to take in configuration data without having to wrap handler.read in a separate callback function on app.get

RouteHandler.prototype = {

    read: function(config){

        return function(req, res){
            //I have access to req, res and config
        }

    }

}

so now I can do this

app.get('route', handler.read("configData"));

instead of this

app.get('route', function(req, res){
    hander.read(req, res, "configData");
});
PaulParton
  • 1,013
  • 1
  • 11
  • 19