Node.js inherits - javascript

I'm doing a REST API using node with hapijs. So, I have to use inherits and I haven't success to access father's functions. I have this:
controller.js
var __ = require('underscore');
var Controller = function(){
var Validator = require('../validators/'+this.controller);
Controller.prototype.validate = new Validator();
}
Controller.prototype.returnErrors = function(err){
var errors = [];
__.each(err, function(error){
errors.push(error.message);
});
return errors;
}
module.exports = Controller;
reckon.js
var __ = require('underscore'),
reckon = require('../components/reckon'),
inherits = require('util').inherits,
Controller = require('./controller'),
Reckon = require('../models/reckon').Reckon;
var ReckonCtr = function() {
this.controller = "reckon";
ReckonCtr.super_.call(this);
}
inherits(ReckonCtr, Controller);
ReckonCtr.prototype.get = function (request, reply, server, callback) {
this.validate.get(__.extend({company:request.params.company}, request.query), function(validation, value){
if(validation.error){
return callback(this.returnErrors(validation.error.details));
}
reckon.getReckon(request.params.company, request.query, function(error, success){
if(error) return callback(error);
return callback(null, success);
});
});
}
module.exports = new ReckonCtr();
Why I can access "this.validate" and can't "this.returnErrors"? (TypeError: Uncaught error: Object # has no method 'returnErrors').
And how about turn my returnErrors private?
Thanks in advance

This is a scoping problem.
You can access this.validate because you are in the context of the ReckonCtr.prototype.get method in which this refers to the instance. However, when you attempt to access this.returnErrors you are in the context of the callback of this.validate.get where this no longer points to the instance.
The simplest, most common, way around this problem is to take a reference to this as a local variable and refer to the variable rather than this directly e.g.
ReckonCtr.prototype.get = function (request, reply, server, callback) {
var self = this;
self.validate.get(__.extend({company:request.params.company}, request.query), function(validation, value){
if(validation.error){
return callback(self.returnErrors(validation.error.details));
}
reckon.getReckon(request.params.company, request.query, function(error, success){
if(error) return callback(error);
return callback(null, success);
});
});
}

this.validate is being used in a context where this refers to the ReckonCtr object so it works. In the callback, this does not refer to ReckonCtr.
Confusion over what exactly this refers to in a given context is a big problem in JavaScript. There are several solutions. This list is no doubt incomplete:
In a function that contains the callback function, save a reference to this with something like var self = this; and then use self in the callback rather than this.
If you're on a recent version of Node, you can use fat arrow syntax to make this more predictable.
Use bind(), call(), or apply() to explicitly set the value of this.
If the object you want is a singleton, just use the object explicitly rather than this.

Related

Function inside object is not a function

this is my object
var Controller = (function () {
var self = this;
self.get = function (req, res) {
res.send({
success: 'you got me'
});
}
return self;
})()
module.exports = Controller;
and below is how i am trying to pass parameters to the get function from another document.
var Controller = require('../Controller.js');
Controller.get(arg1, arg2);
However nodejs throws 'TypeError: Controller.get is not a function', what am i doing wrong here? Thanks
There are several issues with that code, but it will not cause the TypeError: Controller.get is not a function you describe.
The way you're calling your anonymous function that creates Controller means that this within it will be the global object (loose mode) or undefined (strict mode). Let's assume loose mode as you haven't said you're getting an error assigning get to undefined. That means you're creating a global function called get. It also means that Controller returns the global object.
Neither of those is a good thing. :-)
If you want to export an object with a get function, you don't need to do anything nearly so complicated:
var Controller = {
get: function (req, res) {
res.send({
success: 'you got me'
});
}
};
module.exports = Controller;
Or perhaps
function get() {
res.send({
success: 'you got me'
});
}
module.exports = { get: get };
Since this is in the context of a NodeJS module, that doesn't define a global function (modules are called in a private scope).
Or, if you meant Controller to be a constructor, then you need to call it via new and reorganize it slightly:
function Controller() {
var self = this; // If you need it for something, you don't in your example
self.get = function get() {
res.send({
success: 'you got me'
});
};
}
module.exports = Controller;
then use it via new:
var Controller = require('./.Controller.js');
var c = new Controller();
c.get("foo", "bar");
It's also probably worth pointing out that require('../Controller.js') uses the Controller.js file from the parent directory, not the current directory. Just in case that wasn't on purpose and you're getting the TypeError: Controller.get is not a function because you're getting the wrong file.

javascript issue with namespace, "this" and a library

I'm building a visualization page (with dc.js) for which I decided to make the jump and gather it all into a single namespace. Coming from Python's simplicity, crashing against JavaScript's scope madness has been tough enough, so please bear with me.
I have a general JS structure as follows:
var NamespaceClass = function() {
this.var0 = "something";
this.var1 = dc.SomeChartClass("#some-css-selector");
this.setup = function(error, config, dataset) {
console.log("Inside setup:", this);
this.var2 = this.process_data(dataset);
// Do some more stuff...
}
this.process_data = function(data) {
var whatever;
//Do stuff with "data"...
return whatever;
}
this.start = function() {
console.log("Inside start:", this);
var q;
q = queue().defer(d3.json, "config.json")
.defer(d3.csv, "data.csv");
q.await(this.setup);
}
}
var MyNamespace = new NamespaceClass();
MyNamespace.start();
where queue is Mike Bostock's queue lib for asynchronous file queueing. When I try to test the script, I get in the console:
Inside start: Object { var0 = "something", var1={...}, more...}
Inside setup: Window testpage.html
TypeError: this.process_data is not a function
So, invoking setup from q.await makes it loose the object's scope (or whatever this is called in JavaScript...). How can I avoid this? I have also tried using a proxy object like:
this.start = function() {
console.log("Inside start:", this);
var q, proxy;
q = queue().defer(d3.json, "config.json")
.defer(d3.csv, "data.csv");
proxy = this.setup;
q.await(proxy);
}
to no avail!
The value of this is determined by how you call the function that contains it. You have no control over how the setup function is called, since it is called inside the q.await function.
When you do q.await(this.setup), you pass a reference to the function setup, but "lose" any connection to your namespace. You need to bind the function to the namespace for it to have the proper this value:
q.await(this.setup.bind(this));
Even better, since all your functions work only if this is the namespace, you should bind them to the namespace like this:
this.start = function() {
// body
}.bind(this);
// usage:
q.await(this.setup);
And now wherever you pass them, they will have the correct this inside.
Note: in this situation, bind works something like this:
this.start = function() {
var namespace = this;
q.await(function(){ namespace.setup(); });
}

module.exports function undefined when passing in a variable

In my Node.js app, I'm passing in variables to functions by using require like so:
console.log(require('../controllers/controller')(variable)); // undefined
However, when I don't pass in the variable, it logs as a function, like so:
console.log(require('../controllers/controller')); // [Function]
My controllers are defined like this:
var Controller = function (variable) {
this.variable = variable;
};
Controller.prototype.method = function (someInput, callback) {
// can access this.variable;
};
module.exports = Controller;
I also get this error:
TypeError: Object function (variable) {
this.variable = variable;
} has no method 'method'
Any idea as to where I'm going wrong here? I'm stuck at this step and not sure how to debug further.
require('../controllers/controller') is a function. When you use it without new keyword it does not return anything. But when you use new function() it acts like a constuctor of the object. So what you want to do is to use new keyword if you need an object to be returned with its prototype methods.
var Controller = require('../controllers/controller'),
controller = new Controller(variable);
this is an old thread, but I had this issue and the accepted answer didn't help me.
To create a module with a parameter, I use this code:
module.exports = function(pName) {
return {
test1: function() {
console.log('In test 1 '+pName);
},
test2: function() {
console.log('In test 2 '+pName);
}
};
};
And to call the module's functions:
var testModule = require('testModule')('David');
testModule.test1();
testModule.test2();

how to set a this.var from a class inside a function that's in that class?

I want to set the this.session variable from within the last this.rpc via this.setSession() but this is 't working for me:
anyone got an answer for me? I'm still learning javascript classes and coming from php classes, it suprises me that this is'nt working.
function glpirpc(host,user,pass){
this.host = host;
this.session = "";
this.user = user;
this.password = pass;
this.setSession = function(s){
this.session = s;
}
this.rpc = function(method,params,callback) {
var args = {};
args.host = this.host;
console.log('session:' + this.session);
if (this.session != ""){
console.log('get session');
this.host += "?session=" + this.session;
}
args.session = _this.session;
args.method = method;
args.params = params;
$.post('glpirpc/',args,function(data){
if (typeof data.error != "undefined"){
alert(data.error);
}else {
callback(data.return)
}
},"json");
}
this.rpc('glpi.doLogin',{
'login_name': this.user,
'login_password': this.password,
},function(data){
this.setSession(data.session)
});
}
The strange thing about "methods" in JavaScript is that their this object can be anything or nothing, and its value depends only on how the function is called, not whether it's called from another method. When you do callback(data.return), that's a plain function call, not a method call, so it doesn't get a this object.
Instead do callback.call(this, data.return) so that the callback is invoked with the same this object as the function that called it.
To elaborate a little: when you write something like myobject.mymethod() in JavaScript, two things happen: first the interpreter looks up the mymethod property of myobject, and then calls it with myobject as the context. It's equivalent to writing myobject.mymethod.call(myobject). But when you use a function's call() method, you can specify a different context object — e.g. myobject1.mymethod.call(myobject2), which will find the function via myobject1, but when the function runs, its this will be myobject2.
When you call a plain function, not on an object — callback(data.return) as opposed to someobject.callback(data.return) — its context will be the global window object. And you can't call it with this.callback(data.return) because the function isn't stored as a property of the this object. So instead you use callback.call(this, data.return) to specify that the current function's context (its this) should also be the context in which the callback runs.
You can use jQuery.proxy() for this.
this.rpc('glpi.doLogin',{
'login_name': this.user,
'login_password': this.password,
},
$.proxy(function(data) {
this.setSession(data.session)
}, this));

var vs this in Javascript object

I'm developing a web framework for node.js. here is the code;
function Router(request, response) {
this.routes = {};
var parse = require('url').parse;
var path = parse(request.url).pathname,
reqRoutes = this.routes[request.method],
reqRoutesLen = reqRoutes.length;
..... // more code
};
Should I change all the var to this, like so:
function Router(request, response) {
this.routes = {};
this.parse = require('url').parse;
this.path = this.parse(request.url).pathname;
this.reqRoutes = this.routes[request.method];
this.reqRoutesLen = this.reqRoutes.length;
..... // more code
};
Any comments?
Add properties to this when you want the properties to persist with the life of the object in question. Use var for local variables.
edit — as Bergi notes in a comment, variables declared with var don't necessarily vanish upon return from a function invocation. They are, and remain, directly accessible only to code in the scope in which they were declared, and in lexically nested scopes.
It on depends what you want to do.
If you declare the variables with var, then they are local to the function and cannot be accessed outside.
If you assign the variables to this, then they will be set as properties of the context object the function is called on.
So if e.g. if you write:
var obj = new Router();
then obj will have all the variables as properties and you can changed them. If you call
somobject.Router()
then all the variables will be set as properties of someobject.
You can think of properties hung from this sort of like instance variables in other languages (sort of).
It looks like you're creating a constructor function and will likely add some prototype methods. If that's the case, and you need access to routes, you've got it, but not path.
Router.prototype = {
doSomething: function(){
this.routes; // available
path; // not available
}
}
Using var in the constructor is usually used for private variable while using this. is used for public variable.
Example with this. :
function Router() {
this.foo = "bar";
this.foobar = function () {
return this.foo;
}
}
var r = new Router();
r.foo // Accessible
Example with var :
function Router() {
var _foo = "bar";
this.foobar = function () {
return _foo;
}
}
var r = new Router();
r._foo // Not accessible

Categories