Access object properties from prototype - javascript

I have a class that wraps a mongodb client for node.js. The the class below when I call findUsers I get that this.collection is undefined.
How do I access this.collection from the prototype?
Thank you!
Class:
var Users;
Users = (function () {
function Users(db) {
db.collection('users', function (err, collection) {
this.collection = collection;
});
}
Users.prototype.findUsers = function (callback) {
this.collection.find({}, function (err, results) {
});
}
return Users;
})();
Usage:
//db holds the db object already created
var user = new Users(db);
user.findUsers();

You are doing it right in the prototype method, your error is in the callback function of db.collection().
var Users = (function () {
function Users(db) {
var that = this; // create a reference to "this" object
db.collection('users', function (err, collection) {
that.collection = collection; // and use that
});
}
Users.prototype.findUsers = function (callback) {
this.collection.find({}, function (err, results) {
});
}
return Users;
})();

Use another reference:
Users = (function(){
var that = this;
function users(db)
{
db.collection('users', function(err, collection)
{
that.collection = collection;
}
}
})();

Related

Make multiple callbacks from node js asynchronous function

How can I return a object of data returned by asynchronous function called multiple times from within a asynchronous function.
I'm trying to implement like this :
var figlet = require('figlet');
function art(dataToArt, callback)
{
var arry[];
figlet(dataToArt, function(err, data) {
if (err) {
console.log('Something went wrong...');
console.dir(err);
return callback('');
}
arry[0] = data;
callback(arry);
});
figlet(dataToArt, function(err, data) {
if (err) {
console.log('Something went wrong...');
console.dir(err);
return callback('');
}
arry[1] = data;
callback(arry);
});
}
art('Hello World', function (data){
console.log(data);
});
How can I do it correctly, I searched and searched but couldn't find a solution.
Ps. I'm using Figlet.js
I don't know if you're ok using an external module, but you can use tiptoe.
Install it using npm install tiptoe like any regular module and it basically goes like this:
var tiptoe = require('tiptoe')
function someAsyncFunction(obj, callback) {
// something something
callback(null, processedData);
}
tiptoe(
function() {
var self = this;
var arr = ['there', 'are', 'some', 'items', 'here'];
arr.forEach(function(item) {
someAsyncFunction(item, self.parallel());
});
},
function() {
var data = Array.prototype.slice.call(arguments);
doSomethingWithData(data, this);
},
function(err) {
if (err) throw (err);
console.log('all done.');
}
);
the someAsyncFunction() is the async function you want to call does something and calls the callback parameter as a function with the parameters error and data. The data parameter will get passed as an array item to the following function on the tiptoe flow.
Did it Myself :) Thanks to mostafa-samir's post
var figlet = require('figlet');
function WaterfallOver(list, iterator, callback) {
var nextItemIndex = 1;
function report() {
nextItemIndex++;
if(nextItemIndex === list.length)
callback();
else
iterator([list[0],list[nextItemIndex]], report);
}
iterator([list[0],list[1]], report);
}
var FinalResult = [];
WaterfallOver(["hello","Standard","Ghost"], function(path, report) {
figlet.text(path[0], { font: path[1] }, function(err, data) {
if (err) {
FinalResult.push("Font name error try help");
report();
return;
}
data = '<pre>.\n' + data + '</pre>';
FinalResult.push(data);
report();
});
}, function() {
console.log(FinalResult[0]);
console.log(FinalResult[1]);
});

Share updated variable with factory (variable scope)

I would like to share an updated variable (updated from a function) through a factory (Angularjs)
I have the following factory:
appTspSrv.factory('shared', function(db) {
var entities;
var getEntities = function(){
db.query('getEntities', function(err, doc) {
if (err) {
console.log(err);
} else {
entities = doc.rows;
}
});
};
getEntities();
return {
getEntities: function() {
return entities;
}
}
});
When I call my factory's function from the controller I get 'undifined':
console.log(shared.getEntities());
Why is that and how can I fix this?

What is wrong with my async.series

I am trying to execute an async series in nodejs with https://github.com/caolan/async#series :
async.series([
function getLightsId(callback) {
args = {
path: {
"username": "username"
}
};
client.registerMethod("getLightState", "http://bridgeip/api/${username}/lights/", "GET");
client.methods.getLightState(args, function (data, response) {
var ids = [];
for (key in data) {
ids.push(key);
}
callback(null, ids);
});
},
function getLightsState(ids, callback) {
var lightsState = new Object();
async.each(ids, function (id) {
getLightState(id, function (state) {
lightsState[id] = state;
});
});
callback(null, lightsState);
}
], function (err, result) {
console.log(result);
});
but its returning me this error :
callback(null, lightsState); TypeError : undefined is not a function.
I dont understand why..
How do i pass my object lightsState to my other function ?
You won't get ids in your second task, but you'll get a callback as is described in docs.
You could do:
async.series([
function getLightsId(callback) {
args = {
path: {
"username": "username"
}
};
client.registerMethod("getLightState", "http://bridgeip/api/${username}/lights/", "GET");
client.methods.getLightState(args, function (data, response) {
var ids = [];
for (key in data) {
ids.push(key);
}
callback(null, ids);
});
},
], function (err, result) {
var ids = result[0]
var lightsState = new Object();
async.each(ids, function (id) {
getLightState(id, function (state) {
lightsState[id] = state;
});
});
});
But this goes against the conventional use-case of async.series, you only have one async task there.
What you're after for is probably async.waterfall - so here's how that would look like:
async.waterfall([
function getLightsId(callback) {
args = {
path: {
"username": "username"
}
};
client.registerMethod("getLightState", "http://bridgeip/api/${username}/lights/", "GET");
client.methods.getLightState(args, function (data, response) {
var ids = [];
for (key in data) {
ids.push(key);
}
callback(null, ids);
});
},
function getLightsState(ids, callback) {
var lightsState = new Object();
async.each(ids, function (id) {
getLightState(id, function (state) {
lightsState[id] = state;
});
}, function(err) {
callback(err, lightsState)
});
}
], function (err, result) {
console.log(result);
});
Oh, and I thought that async.each needed a callback. I'm not sure, maybe it was you intention not to be so?
its returning me this error: callback(null, lightsState); TypeError : undefined is not a function.
Because callback is not a function. Only the first argument that is passed to your function getLightsState(ids, callback) { is one. Check the docs for series:
tasks - An array or object containing functions to run, each function is passed a
callback(err, result)
series(tasks) runs the functions in the tasks array in series, each one running once the previous function has completed.
In contrast, these are the docs for the waterfall function - which is what you want:
Runs the tasks array of functions in series, each passing their results to the next in the array.
Btw,
var lightsState = new Object();
async.each(ids, function (id) {
getLightState(id, function (state) {
lightsState[id] = state;
});
});
callback(null, lightsState);
is unlikely to work, you probably want to use reduce instead:
async.reduce(ids, {}, function(lightsState, id, rcallback) {
getLightState(id, function(state) {
lightsState[id] = state;
rcallback(null, lightsState);
});
}, callback);

node.js and async module error

I am getting an undefined variable in my code and not sure what the error in my code is:
I get client as undefined when I call getClient...
I have a soap client creation singleton and I have:
var mySingleton = (function() {
var soap = require('soap');
var async = require('async');
var instance;
var client;
function init() {
var url = "http://172.31.19.39/MgmtServer.wsdl";
var endPoint = "https://172.31.19.39:9088";
var options = {};
options.endpoint = endPoint;
async.series([
function(callback) {
soap.createClient(url, options, function (err, result){
console.log('Client is ready');
client = result;
client.setSecurity(new soap.BasicAuthSecurity('admin-priv', 'password'));
callback();
});
}
],
function(err) {
if (err)
return next(err);
});
return {
getClient : function() {
console.log("I will give you the client");
**return client;**
},
publicProperty : "I am also public",
};
};
return {
getInstance : function() {
if (!instance) {
instance = init();
}
return instance;
}
};
})();
module.exports = mySingleton;
so my consumer is :
var soapC = mySingleton.getInstance();
var mySoapClient = soapC.getClient();
I get mySingleton.client is undefined.
Why?
Sure there are better solutions than this one, but it shows you that it can be implemented easier (without async, without singleton):
var soap = require('soap');
var client;
var url = "http://172.31.19.39/MgmtServer.wsdl";
var options = {
endpoint: "https://172.31.19.39:9088"
};
module.exports = {
getClient: function (callback) {
if (client) {
callback(null, client);
return;
}
soap.createClient(url, options, function (err, result) {
if (err) {
callback(err);
return;
}
console.log('Client is ready');
client = result;
client.setSecurity(new soap.BasicAuthSecurity('admin-priv', 'password'));
callback(null, client);
});
},
publicProperty: "I am also public"
};
And when using the client:
// using the client
var mySoapServer = require('./path/to/above/code.js');
mySoapServer.getClient(function (err, client) {
if (err) { /* to error handling and return */ }
client.someRequestMethod(myEnvelope, function (err, response) {
// ...
});
});
There might be a problem when your Soap-Clients gets into trouble (there is no logic to reconnect in case of error). For this you could have a look at the source code of Redis-Client, MySQL-Client, MongoDB-Client, ...
Edit
Some comments on the different aproaches:
The Singleton-pattern is not needed here. Node will execute this JS file only once and further requires get only a reference to the exports. There is no need to create an IIFE scope - the variables won't be visible outside, only the exports.
Programming in Node.js is (besides some special cases) an all-async way. If not done consequently, it just doesn't work or fails/succeeds only if you have good/bad luck.
Error handling looks very much like a lot of boilerplate, but it's necessary in most cases.

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