I've been trying for the last hour to write a user module for passport.js with the findOne, findOneOrCreate, etc. methods, but can't get it right.
User.js
var User = function(db) {
this.db = db;
}
User.prototype.findOne(email, password, fn) {
// some code here
}
module.exports = exports = User;
app.js
User = require('./lib/User')(db);
User.findOne(email, pw, callback);
I've been through dozens of errors, mostly
TypeError: object is not a function
or
TypeError: Object function () {
function User(db) {
console.log(db);
}
} has no method 'findOne'
How do I create a proper module with these functions without creating an object/instance of User?
Update
I went over the proposed solutions:
var db;
function User(db) {
this.db = db;
}
User.prototype.init = function(db) {
return new User(db);
}
User.prototype.findOne = function(profile, fn) {}
module.exports = User;
No luck.
TypeError: Object function User(db) {
this.db = db;
} has no method 'init'
A couple of things are going on here, I've corrected your source code and added comments to explain along the way:
lib/User.js
// much more concise declaration
function User(db) {
this.db = db;
}
// You need to assign a new function here
User.prototype.findOne = function (email, password, fn) {
// some code here
}
// no need to overwrite `exports` ... since you're replacing `module.exports` itself
module.exports = User;
app.js
// don't forget `var`
// also don't call the require as a function, it's the class "declaration" you use to create new instances
var User = require('./lib/User');
// create a new instance of the user "class"
var user = new User(db);
// call findOne as an instance method
user.findOne(email, pw, callback);
You need to new User(db) at some point.
You could make an init method
exports.init = function(db){
return new User(db)
}
And then from your code:
var User = require(...).init(db);
Related
All I am trying to do is to export two functions from a module. One function taking an argument and the other with no argument:
function initClass(params)
{
return new Promise( (resolve, reject) => {
if (!wallet) {
wallet = new WalletClient(params);
resolve(wallet);
} else {
console.log('Wallet is initialized');
resolve(wallet);
}
});
}
function getInstance()
{
return wallet;
}
For initClass(params) only, I can do this as:
module.exports = (params) => {
initClass(params)
}
And then I call this as:
var init = require('./class.js')(params).initClass(params);
This works fine.
Now, for me to export getInstance() as well, I have tried to do the following but it doesn't seem to work.
module.exports = (params) => {
initClass(params),
getInstance
}
This complaints that there is no function getInstance.
Then I tried this:
module.exports.init = (params) => {
initClass(params)
}
module.exports.instance = {
getInstance
}
Then call them as:
var init = require('./class.js').init(params).initClass(params);
What is the proper way to export multiple functions like this?
Thank you.
You're making it more complex than needed. Once you have your functions defined, you can export it with this:
module.exports = {
initClass,
getInstance
}
To use it, you do this:
const init = require("./class.js");
init.initClass(params);
const instance = init.getInstance();
What you're exporting from the module is an object (which I've named init in the example above) that contains two functions. You don't have to pass arguments to the functions at the time you require.
module.exports is basically an object with keys which can refer to any variables/functions of your file.In your case,
module.exports.initClass = function (params){
...
}
module.exports.getInstance = function (){
}
When importing it
var init = require('./class.') // init object has two keys -> initClass and getInstance
init.initClass('abc')
init.getInstance()
If i'm understanding correctly you are trying to export multiple methods if that is the case simple use this.
module.exports = {
method: function() {},
otherMethod: function(parmas) {}
}
In your code use like this.
var init = require('./class.js');
init.method()
init.otherMethond(paramObj)
If you want below scenario you need to check out about method chaining.
var init = require('./class.js').init(params).initClass(params);
I desire to have the following type of object:
const Client = require('./Client')
let client = new Client()
client.someObject.create(...)
client.someObject.update(...)
client.someObject.delete(...)
etc.
This is very easy to accomplish doing something like this:
const Client = function () {
this.someObject = {}
this.someObject.create = function () {...}
this.someObject.update = function () {...}
this.someObject.delete = function () {...}
}
module.exports = Client
But from an organizational standpoint (and because of the massive number of functions someObject has, it would be helpful to put all the someObject stuff into it's own file and require it: require('./someObject'). However, I still need to be able to access the Client object (this) within someObject.create(), someObject.update(), etc.
this.someObject = require('./someObject')
// someObject.js
module.exports = {
create: function () {
// How do I access Client here? Can I pass it to the object literal?
}
}
I've tried to do some prototype sub module type of setup but it doesn't appear to work.
Client.prototype.someObject.create = function () { ... }
How can I separate someObject into it's own file and still access the Client this?
You'll need to provide the Client instance to someObject itself so the latter's methods can use it to reference the former.
One way you accomplish that is to define a 2nd constructor for someObject that takes the client as an argument.
const SomeObject = function (client) {
if (!client) throw new Error('Client reference is required.');
this.client = client;
};
SomeObject.prototype.create = function () {
let client = this.client;
// ...
};
// ....
module.exports = SomeObject;
const SomeObject = require('./someObject');
const Client = function () {
this.someObject = new SomeObject(this);
}
You can also get a similar result with Object.create() if you'd rather keep the object literal:
const baseline = {
create: function () {
let client = this.client;
// ...
},
// ...
};
module.exports = function createSomeObject(client) {
return Object.create(baseline, {
client: {
value: client
}
});
};
const createSomeObject = require('./someObject');
const Client = function () {
this.someObject = createSomeObject(this);
};
I have read a lot of articles about how to create modules in node.js, and you can use module.exports to expose module internals to the file which includes it.. awesome!
How does this work the other way around? I'll use the following as an example :-)
USER.JS
function User() {
this.property = 'value';
this.doSomething = function() {
var getStuff = mainFileFunction();
// do something with getStuff
}
module.exports = User;
MAIN.JS
var myArray = [];
myArray.push('something');
myArray.push('something else');
mainFileFunction() {
for(thing in myArray) {
return myArray[thing];
}
}
var u = new user();
log(u.property); <--- THIS IS EXPOSED, COOL!
u.doSomething(); <--- This will throw an error because mainFileFunction is not defined in user.js :-(
If I were to move mainFileFunction to the user file, then it still wouldn't work because the myArray array wouldn't be defined... and if I were to move that over too, I wouldn't be able to use it in other functions in main (which I want to) :-)
I'm sorry if I'm missing something really obvious here... What I want is to expose the parts of my choosing from modules I include (module.export works for that) but I also want to expose everything from the main file to all the includes..
or just expose everything to everything? is that totally messy and horrible??
Just to explain what I am trying to do here... I want to have classes defined in separate files, but I want to instantiate a bunch of them as objects in the main file and store them in arrays.. I want the objects to contain methods which can access arrays of the other object types.
Thanks guys! :-)
You can use globals, or have a proper circular dependency (requireing both files), however - this is usually a bad habit which can lead to maintainability problems in the future.
Instead, you can use dependency injection and inject doSomething into your module.
This basically gives you the following for free:
You can test User with a simple mock implementation of doSomething later and verify the correctness of your code
The dependencies of a user are explicit and not implicit, which makes it obvious what a user needs.
I'll provide two implementations, one using constructor dependency injection and one with a module wide setting.
USER.JS
function User(dependentFunction) {
this.property = 'value';
this.doSomething = function() {
var getStuff = dependentFunction();
// do something with getStuff
}
}
module.exports = User;
MAIN.JS
...
var u = new User(mainFileFunction);
u.doSomething(); // this will now work, using mainFileFunction
What happens here is fairly simple, and we know what's going on.
This can also be a module wide setting
USER.JS
function User(depFunc) {
this.property = 'value';
this.doSomething = function() {
var getStuff = depFunc();
// do something with getStuff
}
}
function UserFactory(depFunc){
return function(){
return new User(depFunc);
}
}
module.exports = UserFactory;
MAIN.JS
var getUser = UserFactory(mainFileFunction);
var u = getUser(); // will return a new user with the right function
+1 to Benjamin answer for dependency injection.
I would like to add another way to inject objects in your modules by passing the dependency in the require like require('./module.js')(dependentFunction);
//MAIN.js
var db = function() {
this.rows = [];
this.insert = function(name) {
this.rows.push(name);
console.log('Db: Inserting user with name ' + name);
}
this.getAll = function(){
return this.rows;
}
}
var fakeDb = new db();
var user = require('./user.js')(fakeDb);
user.add('Jhon');
user.add('Rose');
user.list();
and
//users.js
module.exports = function(db) {
return {
add: function(name) {
db.insert(name);
},
list: function() {
var users = db.getAll();
var i = users.length;
console.log('listing users\n-------');
while(i--) {
console.log(users[i]);
}
}
}
}
You should pass mainFileFunction as a parameter to the constructor of user.
USER.JS
function User(mainFileFunction) {
this.property = 'value';
this.doSomething = function() {
var getStuff = mainFileFunction();
// do something with getStuff
}
module.exports = User;
In your main.js use the following
var u = new user(mainFileFunction);
How about moving mainFileFunction to user.js, and have the function accept an array as an argument:
mainFileFunction(array) {
for(thing in array) {
return array[thing];
}
}
And then when you call it from main.js, pass the function your array:
u.doSomething(myArray);
Let's say I wanted to have this API for an example to do app:
var db = new Database('db-name'); // DB connection
var todo = new Todo(db); // New "Todo" and pass it the DB ref
// I want this API:
todo.model.create('do this', function (data) {
console.log(data);
});
I have it setup currently like:
function Todo (storage) {
this.storage = storage;
};
Todo.prototype.model = {
create: function (task, callback) {
// The problem is "this" is Todo.model
// I want the "super", or Todo so I can do:
this.storage.save(task, callback);
}
}
So, if you see the comment, the problem is that "this" inside of model.create is obviously referencing Todo.model, but I need it to grab the "super".
Best I could think of was:
Todo.prototype.model = function () {
var self = this;
return {
create: function (task, callback) {
// The problem is "this" is Todo.model
// I want the "super", or Todo so I can do:
self.storage.save(task, callback);
}
}
}
But both of these aren't great. The biggest problem is that I don't want to have all my methods on model inside of a single object (1st example) or function (2nd). I want to be able to take them out from inside of the model def. Secondly, I'd like to have the todo.model.create API.
Is there a design pattern to achieve this?
You can't use the prototype pattern for todo.model as you've written it because model is a property of todo.
I think you need:
a new Model object, on which you can use the prototype model.
in the Todo constructor, create a Model object. Ideally, use a read-only "getter" function to allow that model object to be accessed, but not overwritten.
Using bind, you can do something like this:
function Todo (storage) {
this.storage = storage;
this.model = {};
var methodNames = Object.keys(TodoModel);
for(var i = 0; i < methodNames.length; ++i) {
var methodName = methodNames[i];
var method = TodoModel[methodNames];
model[methodName] = method.bind(this);
}
};
var TodoModel = {
create: function(task, callback) {
// Note that when this method is called using Todo.model.create,
// 'this' will point to the Todo instance.
this.storage.save(task, callback);
}
};
function test(storage) {
var todo = new Todo(storage);
var task = {};
todo.model.create(task, function(err, savedTask) {
// ...
});
}
The TodoModel is basically a map, so you can replace it with a Map collection and you will no longer need to call Object.keys.
You could set up the model in the constructor like in the following example:
function Todo (storage) {
var self = this;
this.storage = storage;
this.model = {
create: function(task, callback) {
self.storage.save(task, callback);
}
};
};
Alternatively, you could use bind, but I think that it would unnecessarily complicate things, because you must find an implementation that works on older browsers and it does not conflict with the native implementation in newer browsers that support EcmaScript 5.
I'm writing a simple server for Node.js and I'm using my own class called User which looks like:
function User(socket) {
this.socket = socket;
this.nickname = null;
/* ... just the typical source code like functions, variables and bugs ... */
this.write = function(object) {
this.socket.write(JSON.stringify(object));
}
};
and then later in the process I'm instantiating it a lot:
var server = net.createServer(function (socket) {
/* other bugs */
var user = new User(socket);
/* more bugs and bad practise */
});
Can I move my User class definition to another javascript file and "include" it somehow?
You can simply do this:
user.js
class User {
//...
}
module.exports = User // 👈 Export class
server.js
const User = require('./user.js')
let user = new User()
This is called CommonJS module.
ES Modules
Since Node.js version 14 it's possible to use ES Modules with CommonJS. Read more about it in the ESM documentation.
user.mjs (👈 extension is important)
export default class User {}
server.mjs
import User from './user.mjs'
let user = new User()
Using ES6, you can have user.js:
export default class User {
constructor() {
...
}
}
And then use it in server.js
const User = require('./user.js').default;
const user = new User();
Modify your class definition to read like this:
exports.User = function (socket) {
...
};
Then rename the file to user.js. Assuming it's in the root directory of your main script, you can include it like this:
var user = require('./user');
var someUser = new user.User();
That's the quick and dirty version. Read about CommonJS Modules if you'd like to learn more.
Another way in addition to the ones provided here for ES6
module.exports = class TEST{
constructor(size) {
this.map = new MAp();
this.size = size;
}
get(key) {
return this.map.get(key);
}
length() {
return this.map.size;
}
}
and include the same as
var TEST= require('./TEST');
var test = new TEST(1);
If you append this to user.js:
exports.User = User;
then in server.js you can do:
var userFile = require('./user.js');
var User = userFile.User;
http://nodejs.org/docs/v0.4.10/api/globals.html#require
Another way is:
global.User = User;
then this would be enough in server.js:
require('./user.js');