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.
Related
When calling a function in the module in this way
app.get("/api/sessions/oauth/google", (req, res) => {
return google_callback.googleOAuthHandler(req, res);
});
this points to the module and another function in the module can be accessed using this
googleOAuthHandler : async function (req, res) {
const code = req.query.code.toString();
const {id_token, access_token} = await this.getGoogleOAuthToken(code);
}
However passing the function as a parameter changes this to global and this.getGoogleOAuthToken becomes undefined
i.e when doing
app.get("/api/sessions/oauth/google", google_callback.googleOAuthHandler);
how would i access getGoogleOAuthToken in googleOAuthHandler in google_callback module when using this way
app.get("/api/sessions/oauth/google", google_callback.googleOAuthHandler);
When passing function this way this doesn't mean the module. So this.getGoogleOAuthToken doesn't work.
however we can use module.exports.getGoogleOAuthToken to access the function within the same module. Using module.exports.getGoogleOAuthToken also works in the first example.
Alternatively if you don't like module.exports to call the function you can place line const _this = this; at the top of the file or const _this = module.exports = { ... } and use _this.function to call a function inside the module.
Also just noticed that in the first example this.function only works because i'm using this syntax.
module.exports = {
func1 : function(){},
func2 : function(){}
}
when exporting with
module.exports.func1 = function(){}
module.exports.func2 = function(){}
this cannot be used to access the other function
I'm new to jasmine. My Company is using jasmine 1.3.1
I am trying to test if a variable is defined in a method. I keep coming back with a failure.
objectParentName.accessoriesSlider = {
modifyJSON: function(obj) {
var contentLoadJSON = [];
for (var property in obj) {
objectParentName.accessoriesSlider.contentJSONTotal++
contentLoadJSON.push(obj[property]);
}
contentLoadJSON = objectParentName.accessoriesSlider.sortJSON(contentLoadJSON, 'dateAdded', false);
return contentLoadJSON;
}
}
Here is jasmine for that method.
describe('Test "modifyJSON" function', function () {
beforeEach(function() {
spyOn(objectParentName.accessoriesSlider, 'modifyJSON');
var contentLoadJSON = []; //forcibly add variable to see if that fixes issue
objectParentName.accessoriesSlider.modifyJSON();
});
it('is defined as "modifyJSON"', function () {
/**
* objectParentName.accessoriesSlider.modifyJSON should be defined.
*/
expect(objectParentName.accessoriesSlider.modifyJSON).toBeDefined();
});
it('and "modifyJSON" is a function', function () {
/**
* This should be a 'function'.
*/
expect(objectParentName.accessoriesSlider.modifyJSON).toBeFunction();
});
describe('Test "contentLoadJSON" variable', function () {
it('is defined', function () {
expect(contentLoadJSON).toBeDefined();
});
});
});
I am getting this error
ReferenceError: contentLoadJSON is not defined
at .<anonymous> (http://localhost:8234/spec/jasmine_accessories_slider.js:300:24)
at jasmine.Block.execute (http://localhost:8234/?spec=accessories_slider.js:1164:19)
at jasmine.Queue.next_ (http://localhost:8234/?spec=accessories_slider.js:2196:33)
at jasmine.Queue.start (http://localhost:8234/?spec=accessories_slider.js:2149:10)
at jasmine.Spec.execute (http://localhost:8234/?spec=accessories_slider.js:2476:16)
at jasmine.Queue.next_ (http://localhost:8234/?spec=accessories_slider.js:2196:33)
at jasmine.Queue.start (http://localhost:8234/?spec=accessories_slider.js:2149:10)
at jasmine.Suite.execute (http://localhost:8234/?spec=accessories_slider.js:2621:16)
at jasmine.Queue.next_ (http://localhost:8234/?spec=accessories_slider.js:2196:33)
at jasmine.Queue.start (http://localhost:8234/?spec=accessories_slider.js:2149:10)
So, I have no idea why I am getting an error here.
The first problem is that the variable contentLoadJSON is not defined in the scope of the function you are calling it from.
When you define a variable using var, it becomes a local variable, and is only accessible inside the scope of that function. In this case, the function it exists in is:
beforeEach(function() {
spyOn(objectParentName.accessoriesSlider, 'modifyJSON');
var contentLoadJSON = [];
objectParentName.accessoriesSlider.modifyJSON();
});
The function you are getting the error in is a different function() { ... } that isn't nested in beforeEach. It is therefore can't see the local variable you defined.
One way to rectify this is by defining the variable in the scope of your test suite, instead of in the scope of the beforeEach function:
describe('Test "modifyJSON" function', function () {
var contentLoadJSON; // Define it here
beforeEach(function() {
contentLoadJSON = []; // Assign it here
// ... more code here ...
}
// ... more code here ...
describe('Test "contentLoadJSON" variable', function () {
it('is defined', function () {
// Test contentLoadJSON here...
The second problem is that just because variables have the same name doesn't mean they are actually the same variable. They have to also be in the same scope for that to be true. var contentLoadJSON inside modifyJSON is actually a totally different variable than the var contentLoadJSON you are defining in beforeEach in your test suite.
When you call the function under test, you are not assigning its result to the variable you are trying to test. In fact, you are actually throwing away the result immediately after you call the function.
To fix this, change:
var contentLoadJSON = [];
objectParentName.accessoriesSlider.modifyJSON();
// Note that contentLoadJSON still equals [] at this point.
// The return of the function call is getting thrown away,
// because you don't assign it to a variable
To:
var contentLoadJSON = objectParentName.accessoriesSlider.modifyJSON();
The third problem is that expect(someVariable).toBeDefined(); might not do what you are expecting it to do. It doesn't check that the variable is "in scope". It checks that the value someVariable is not equal to the value undefined. Unless your function might sometimes return undefined, then this particular test isn't very important and will probably never fail.
It may be better to check that the result is "truthy" (expect(contentLoadJSON).toBeTruthy()). It might even make sense to just check that it is equal to the value you'd expect for the given data/input.
I'm getting a very odd error when I try to require a node module. To illustrate the problem here is the code I am trying to require:
module.exports = (function(){
this.say = function(message) {
console.log(message);
}
})();
Now when I require this module I get 'Cannot read property 'say' of undefined when I try to use it as follows:
var person = require('./Person.js')
person.say('Hello World!');
And yet, if I define the module as follows it works fine ...
module.exports = {
say : function(message) {
console.log(message);
}
};
I even tried this notation that also worked ...
module.exports = new Person();
function Person(){
this.say = function(message) {
console.log(message);
}
};
Does anyone have any idea why the first notation doesn't work properly?
The reason is your first notation doesn't return anything to export.
module.exports = (function(){
this.say = function(message) {
console.log(message);
}
return this;
})();
I guess this should solve your problem.
module.exports is an object that will be returned upon require calls for that file.
So assume you want write a library that does some logic, some is private, other is public.
and you want to expose only your public function to other people to invoke,
what your file may look like is:
// Some require calls you maybe using in your lib
function privateFunc(s) {
console.log(s);
}
function publicFunc(s) {
privateFunc("new log: " + s);
}
module.exports = {
log: publicFunc
}
You later will use it as follows:
var logger= require('myLib');
logger.log("my log");
This will output:
new log: my log
Thats maybe deeper than what you actually wanted, but it is meant to understand the flow of things
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.
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();