nodeStack.getFunctionName() returns null - javascript

I have the following node.js code:
var path = require('path');
var nodeStack = require('stack-trace');
var controller = (function () {
function controller() {
}
controller.prototype.render = function (res, model, view) {
var stack = nodeStack.get();
var frame = stack[1];
var functionName = frame.getFunctionName().split(/controller\./i);
if (functionName.length < 2) {
functionName = frame.getFunctionName().split(/(controller|\./i);
}
if (!view) {
view = functionName[1];
var dotidx = view.indexOf('.');
if (dotidx > -1) {
view = view.substring(0, dotidx);
}
}
if (!model) {
model = {};
}
var base = '';
if (res.locals.basePath) {
base = res.locals.basePath;
}
var cls = functionName[0];
res.render(path.join(base, cls, view), model);
};
return controller;
})();
module.exports = controller;
The code should allow me to render a view based on the method, the matching file should be found automatically.
It works all fine, just in one case frame.getFunctionName() returns null.
The code for the subclasses look as follows:
customerController.prototype.add = function (req, res) {
var _this = this;
somepromise.then(function (provider) {
return provider.getCP();
}).then(function (cp) {
controller.prototype.render.call(_this, res, { title: 'add customer', contactpersons: cp });
}, function (err) {
controller.prototype.render.call(_this, res, { title: 'add customer' });
});
};
The one code that doesn't work.
customerController.prototype.details = function (req, res) {
var _this = this;
somepromise.then(function (provider) {
return provider.getCustomerById(req.param('id'));
}).then(function (customer) {
_super.prototype.render.call(_this, res, { title: 'customer details', customer: customer });
}, function (err) {
res.status(404).send(err);
});
};
The code works for all methods except one. Do you have an idea why?
Remarks: The code is compiled from TypeScript

Related

ExpressJS Router + Promise not working

I have a problem with Express response and Promise.
My script call a MongoDB Database to get informations from the server. I use Promise to send the result only when my server answered me.
The problem is in my route. I get the response correctly, but the
res.send returns nothing. I can't figure why.
Let's review my code. I've truncated some of the files, as it is not important code.
I have first a server.js file with my router declaration :
let router = express.Router();
app.use('/mongo', MongoRouter);
Then here is my MongoRouter.js file :
import { Router } from 'express';
import { MongoController } from '../Controllers/MongoController';
class MongoRouter {
constructor() {
this.router = Router();
this.controller = new MongoController();
this.routes();
}
routes() {
let obj = this;
this.router.get('/global', (req, res) => {
let promise = obj.controller.globalInfos();
promise.then((value) => {
console.log('Resolve OK. Showing data');
console.log(value);
res.send(value);
}).catch((error) => {
res.status(500).send(error.toString());
});
});
this.router.get('*', (req, res) => {
res.json({
data: 'Invalid route'
});
});
}
}
export default new MongoRouter().router;
And the function globalInfos() from my MongoController :
globalInfos() {
var status = '';
var globalInfos = new Array();
var internalServerReached = 0;
var dbCommand = {'serverStatus': 1};
let obj = this;
return new Promise((resolve, reject) => {
obj.cnxStrings.forEach(element => {
MongoClient.connect(element['cnxString'], (err, db) => {
if (!err) {
if (element['replica'] == true) {
dbCommand = {'replSetGetStatus':1};
}
db.command(dbCommand, (err, results) => {
if (!err) {
status = results;
} else {
status = 'Status unknown';
}
globalInfos[element['name']] = status;
internalServerReached++;
db.close();
if (internalServerReached >= obj.cnxStrings.length) {
console.log('Waiting 3s for the resolve');
setTimeout(() => {
resolve(globalInfos);
},3000);
}
});
} else {
status = 'Unreachable';
}
});
});
});
}
When i go to http://localhost:3000/mongo my function is running, the resolve is called after 3sec, my data are ok in the console (in the .then() callback), but the res.send(..) show an empty array []
Thanks!

Sending array data from server to client in Meteor

So I'm trying to send my data from my server code to my client code, yet it's returning undefined. Not sure what to do as I've been stuck here for a while.
I used these packages:
https://github.com/meteorhacks/npm
https://www.npmjs.com/package/wiki-infobox
Rappers = new Mongo.Collection(null)
var page = 'Tupac'
var language = 'en'
var rappers = null
var texts
var rappers2
if (Meteor.isClient) {
getGists = function getGists(user, callback) {
Meteor.call('getGists', user, callback);
}
Meteor.startup(function() {
rappers2 = []
function call(text, callback) {
Meteor.call('getWikiStuff', rappers2, function(err, result) {
console.log(result)
})
var timer = setTimeout(function() {
callback()
}, 4000)
}
function consoleit() {
console.log(rappers2)
}
call('hello', consoleit)
})
}
if (Meteor.isServer) {
Meteor.startup(function() {
Meteor.methods({
getWikiStuff: function(rappers3) {
var infobox = Meteor.npmRequire('wiki-infobox')
var bound = Meteor.bindEnvironment(function(callback) {
callback()
});
console.log("HERE")
bound(function() {
infobox(page, language, function(err, data) {
if (err) {
return
}
rappers = data.associated_acts
for (var x = 0; x < rappers.length; x++)
if (rappers[x].text != undefined) {
var yo = rappers[x].text
rappers3.push(yo)
}
for (var value of rappers3)
console.log(value)
})
})
return rappers3
}
})
})
}

Access prototype value from prototype function

How do I access open array that is prototyped from removeConnection() function? Right now I get ReferenceError: open is not defined when I call the function.
function Connections() {}
Connections.prototype.open = [];
Object.defineProperty(Connections.prototype, 'total', {
get: function total() {
return this.open.length;
}
});
Connections.prototype.removeConnection = function(res) {
this.open = open.filter(function(storedRes) {
if (storedRes !== res) {
return storedRes;
}
});
}
var connections = new Connections();
For me it raises a different error Uncaught TypeError: open.filter is not a function and the fix is to change this.open = open.filter to this.open = this.open.filter.
See the runnable example:
function Connections() {}
Connections.prototype.open = [];
Object.defineProperty(Connections.prototype, 'total', {
get: function total() {
return this.open.length;
}
});
Connections.prototype.removeConnection = function(res) {
this.open = this.open.filter(function(storedRes) {
if (storedRes !== res) {
return storedRes;
}
});
}
var connections = new Connections();
connections.open = ['one', 'two']
alert(connections.open)
connections.removeConnection('one')
alert(connections.open)
You're missing this.
Connections.prototype.removeConnection = function(res) {
this.open = this.open.filter(function(storedRes) {
if (storedRes !== res) {
return storedRes;
}
});
}

Node.js module sync to async

I have a simple Node.js module that takes a directory of Handlebars templates, compiles them and then exports an object of them keyed on their name:
'use strict';
var
fs = require('fs'),
path = require('path'),
handlebars = require('handlebars'),
templateDir = __dirname + '/templates/',
templates = {};
fs.readdirSync(templateDir).forEach(function (file) {
templates[path.basename(file, path.extname(file))] =
handlebars.compile(fs.readFileSync(templateDir + file));
});
module.exports = templates;
So then in other modules I can just:
var templates = require('./templates');
templates[SOME_TEMPLATE]({ ... });
I'm struggling on how to do this asynchronously though, specifically how to export with an emitter in the mix.
var emitter = require('events').EventEmitter;
module.exports = function (callback) {
emitter.on('templates-compiled', function () {
callback(templates);
});
callback();
};
fs.readdir(templateDir, function (err, files) {
if (!err) {
files.forEach(function (file) {
fs.readFile(templateDir + file, function(err, data) {
if (!err) {
templates[path.basename(file, path.extname(file))] =
handlebars.compile(data);
if (files[files.length - 1] === file) {
emitter.emit('templates-compiled');
}
} else {
}
});
});
} else {
}
});
Heres a modification of the above that works:
var EventEmitter = require('events').EventEmitter;
var path = require('path');
var fs = require('fs');
module.exports = function(dir, callback) {
var emitter = new EventEmitter();
var templates = {};
emitter.on('templates-compiled', function(t) {
callback(null, t);
});
emitter.on('templates-error', function(e) {
callback(e);
});
fs.readdir(dir, function(err, files) {
if (!err) {
files.forEach(function(file) {
fs.readFile(path.join(dir, file), function(err, data) {
if (!err) {
//note: i'm just calling toString() here - do your compile here instead
templates[path.basename(file, path.extname(file))] = data.toString();
if (files[files.length - 1] === file) {
emitter.emit('templates-compiled', templates);
}
} else {
emitter.emit('templates-error', err);
}
});
});
} else {
emitter.emit('templates-error', err);
}
});
};
However you may want to look at using q or async to trim down the pyramid of doom.

This scope lost with inheritance

Here is the example code, two files and "classes".
CRUD class with defined methods, the problem occurs with this.modelName, as I set the routes the this context changes with this code:
The question is how, to get the same scope under the CRUD where you have defined the modelName ?
server.get('/users/:id', UserRoutes.find);
Code:
var db = require('../models');
function CRUD(modelName) {
this.modelName = modelName;
this.db = db;
}
CRUD.prototype = {
ping: function (req, res, next) {
res.json(200, { works: 1 });
},
list: function (req, res, next) {
// FAILS BECAUSE the modelName is undefined
console.log(this);
db[this.modelName].findAll()
.success(function (object) {
res.json(200, object);
})
.fail(function (error) {
res.json(500, { msg: error });
});
}
};
module.exports = CRUD;
UserRoutes class:
var CRUD = require('../utils/CRUD'),
util = require('util');
var UserModel = function() {
UserModel.super_.apply(this, arguments);
};
util.inherits(UserModel, CRUD);
var userRoutes = new UserModel('User');
module.exports = userRoutes;
I assume that you are using userRoutes.list as a handler somewhere else, i.e. the context changes. In that case this should be a simple solution:
function CRUD(modelName) {
this.modelName = modelName;
this.db = db;
this.list = CRUD.prototype.list.bind(this);
}
Note that you won't be able to access "the other this" with that solution (this will be permamently bound to CRUD instance, no matter how .list is called).
The other option is to turn list into a function generator (which is pretty much the same what .bind does, except you can still use this from the other context):
CRUD.prototype = {
// some code
list: function() {
var that = this;
return function (req, res, next) {
console.log(that);
db[that.modelName].findAll()
.success(function (object) {
res.json(200, object);
})
.fail(function (error) {
res.json(500, { msg: error });
});
}
}
};
and then use userRoutes.list() as a handler.
This sort of thing is generally fixed by stowing the right this into _this. In your list function this is the function object, which doesn't have a modelName object.
var _this;
function CRUD(modelName) {
this.modelName = modelName;
this.db = db;
_this = this // <---------------
}
....
// call the _this in the outer scope
db[_this.modelName]

Categories