app.js
app.get('/save', function(req,res){
var switchInput = {
sw1: req.query.switch1,
sw2: req.query.switch2,
sw3: req.query.switch3,
sw4: req.query.switch4,
sw5: req.query.switch5,
sw6: req.query.switch6,
}
console.log(switchInput);
module.exports = switchInput
res.send(switchInput);
});
simulate.js
var mongoose = require('mongoose');
var suit = require('../app')
...
function batteryLife(t){
var elapsed = Date.now() - t;
t_remaining = fullTime - elapsed;
t_battery = secondsToHms(Math.floor(t_remaining/1000));
//console.log(Math.floor(elapsed/1000) + ' s');
console.log(suit.sw1);
return t_battery;
};
Console Log:
{ sw1: 'true',
sw2: 'true',
sw3: 'true',
sw4: 'true',
sw5: 'true',
sw6: 'true' }
--------------Simulation started--------------
undefined
undefined
undefined
undefined
--------------Simulation stopped--------------
When I try to access these values from a different js file they print as undefined I am using postman to simulate values
The values will log from here but print undefined from the other js file
Is there a way to correct this I'm not sure what I am doing wrong
the values are loading into "inputSwitch" but are not coming out on the simulate.js side
First of all, while using youre favorite webserver like Express, you request aka (req) will/could flow amongst middleware before reaching your specific endpoint. Which means your req params are accessible at anytime there which could help you for specific code logic middleware-the-core-of-node-js-apps.
I agree with vibhor1997a, you should not export something there, basically you only module.exports "things" at the end of a file, not something at run-time.
You could do if you really want to deal with switchInput in another file do :
do what vibhor1997a suggest (sync or async function)
have a middleware before reaching your endpoint
raised an event with your switchInput as argument example
You're exporting on an event which isn't a good idea. What you can do instead is call a function in the other file where you need values with the values.
Example
app.js
const simulate = require('./simulate');
app.get('/save', function(req,res){
var switchInput = {
sw1: req.query.switch1,
sw2: req.query.switch2,
sw3: req.query.switch3,
sw4: req.query.switch4,
sw5: req.query.switch5,
sw6: req.query.switch6,
}
simulate(switchInput);
res.send(switchInput);
});
simulate.js
module.exports = function(input){
//have all your functions and code that require input here
function foo(){...}
function bar(){...}
}
Related
I wanted to write a understandable code in node.js, so I want to put some functions, which are used very often, into other node.js files, and access them from there.
So I get a function, which calls a function from another node.js file and in this other node.js file, also another one is called.
Important to know, if I put all in one file, the code works, so it should be an issue with module export and using functions in another file.
I have one file, getting quotes from a decentralised exchange. Looking like this (quoter_uni_v2.js):
module.exports = function quotes_uni_v2(tokenIn, tokenOut, amountIn, router) {
const quotedAmountOut = router.getAmountsOut(amountIn.toString(), [
tokenIn,
tokenOut,
]);
return quotedAmountOut;
};
And I am importing this function in my second helper file (quotes_5.js) (It is splitted in two files, because in the second one I have to call the function multiple times):
var quotes_uni_v2 = require("./quotes_uni_v2");
module.exports = async function (router1, router2, route, amount_wei) {
console.log(route);
var amount_Out = await quotes_uni_v2.quotes_uni_v2(
route[1],
route[2],
amount_wei,
router1
);
...
return (
Math.round(ethers.utils.formatEther(amount_Out[1].toString()) * 100) / 100
);
};
After that I try to call the function in my main.js:
const quotes_uni_v2 = require("./quotes_uni_v2");
const quotes_5 = require("./quotes_5");
async function calc(route) {
amountOut = await new quotes_5(
quickswap_router,
sushiswap_router,
route,
amount_wei
);
return amountOut;
};
But calling the quotes function does not work... The error is:
TypeError: quotes_5 is not a constructor...
Can someone help me?
Thanks!
I am on my way to separate the code for my API in different modules using the exports object, as it is the most similar way to the ES6 standard (not yet supported by Node).
Here is my code currently (it can be run as shown), the problem is that, after separating, the function "cleanFormData" gets called fine, but stops without returning anything (observe the comments starting with "STACK OVERFLOW"):
File: main.js
// Dependencies:
const express = require('express');
const bodyParser = require('body-parser');
// Define app:
const app = express();
// API v0 code:
const apiV0 = require('./api0_sources/api');
// Configuration variables:
const consoleLogActions = true;
// Server start:
app.listen(8888, function () {
console.log('Server running on port ' + this.address().port + ' - ' + new Date());
});
// For parsing every application/json request:
app.use(bodyParser.json());
// Submit data to register an user:
app.post('/registration', function (req, res) {
res.set({'Content-Type': 'application/json'});
// Clean the required data after obtaining it from the parsed JSON:
let cleanedFormData = apiV0.cleanFormData({ // STACK OVERFLOW: The code stops working here.
username: req.body.formdata.username,
email: req.body.formdata.email,
phone: req.body.formdata.phone,
password: req.body.formdata.password
});
// The "required or not" policy is enforced here (after the strings have been cleaned to prevent blank fields to pass):
errors = [];
if (cleanedFormData.username === undefined) errors.push('username_required');
if (cleanedFormData.email === undefined) errors.push('email_required');
if (cleanedFormData.phone === undefined) errors.push('phone_required');
if (cleanedFormData.password === undefined) errors.push('password_required');
if (errors.length > 0) {
let result = {
success: false,
errors: errors
};
res.jsonp(result);
}
})
// [More things happen after]
File: ./api0_sources/api.js
// Fix and delete object's strings (for data coming from user's inputs):
exports.cleanFormData = function(object) {
for (let i in object) {
object[i] = String(object[i]); // Convert all the object properties to strings (to prevent problems with true, false and null).
if ((object[i] === 'undefined') || (!object[i].replace(/\s/g, '').length)) { // Deletes 'undefined' strings, empty strings and the ones containing only spaces.
delete object[i];
continue; // Skip to the next loop after the property is removed.
}
// Do not try to fix the "password" or "newPassword" property:
if ((i === 'password') || (i === 'newPassword')) continue;
// Replace multiple spaces with a single one:
object[i] = object[i].replace(/\s\s+/g, ' ');
// Check if it is "trimmable" and if so, trim the string:
if (object[i].trim()) object[i] = object[i].trim();
console.log(object[i]) // Observing iterations.
}
if (consoleLogActions) console.log('▼ Cleaned object keys:\n', object);
return object;
};
Before, everything was in the same file and worked perfectly fine! Can someone help me to identify what has triggered this unexpected behaviour?
UPDATED 1: Apparently, I identified the problem: I had a variable not shown in the example before: "consoleLogActions", that was only defined in the main file and apparently this stopped the function in the child module from finishing. However, absolutely no error was being thrown by Node. In the updated example it does, in my actual file it doesn't (still, no idea why).
UPDATE 2: Thanks, Marcos Casagrande. It seems like this Express middleware is catching the wrong exceptions. I had literally no idea that this could affect the rest of the code nor I have idea how to fix it. Any suggestions?:
// Detecting syntax errors (depending on the "application/type"):
app.use(function(err, req, res, next) {
if (err instanceof SyntaxError) { // If "SyntaxError" is part of the error object:
res
.status(400)
.jsonp({
success: false,
errors: ['bad_syntax']
});
}
});
Apparently, I identified the problem: I had a variable not shown in
the example before: "consoleLogActions", that was only defined in the
main file and apparently this stopped the function in the child module
from finishing. However, absolutely no error was being thrown by Node.
In the updated example it does, in my actual file it doesn't (still,
no idea why).
If you're not getting any error, you probably have an express error-handling middleware, that it's not logging the error.
app.use((err, req, res, next) => {
// console.error(err); // I'm not doing this.
res.status(500).end();
});
Or you have an uncaughtException listener somewhere in your code.
process.on('uncaughtException', () => {});
The code above, will prevent uncaught errors from being logged, and the process from crashing. This is a really bad practice, and you should avoid it.
Check the following question:
Node.js Best Practice Exception Handling
I have the following code that does not work currently.
var config = require('./libs/sequelize-lib.js');
var connection = config.getSequelizeConnection();//Choosing to not pass in variable this time since this should only run via script.
var models = config.setModels(connection);//Creates live references to the models.
//Alter table as needed but do NOT force the change. If an error occurs we will fix manually.
connection.sync({ alter: true, force: false }).then(function() {
models.users.create({
name: 'joe',
loggedIn: true
}).then( task => {
console.log("saved user!!!!!");
});
process.exit();//close the nodeJS Script
}).catch(function(error) {
console.log(error);
});
sequelize-lib.js
var Sequelize = require('sequelize');
exports.getSequelizeConnection = function(stage){
var argv = require('minimist')(process.argv.slice(2)); //If this file is being used in a script, this will attempt to get information from the argument stage passed if it exists
//Change connection settings based on stage variable. Assume localhost by default.
var dbname = argv['stage'] ? argv['stage']+"_db" : 'localdb';
var dbuser = argv['stage'] ? process.env.RDS_USERNAME : 'admin';
var dbpass = argv['stage'] ? process.env.RDS_PASSWORD : 'local123';
var dbhost = argv['stage'] ? "database-"+argv['stage']+".whatever.com" : 'localhost';
//If state variable used during require overide any arguments passed.
if(stage){
dbname = stage+"_db";
dbuser = process.env.RDS_USERNAME
dbpass = process.env.RDS_PASSWORD
dbhost = "database-"+stage+".whatever.com"
}
var connection = new Sequelize(dbname,dbuser,dbpass, {
dialect: 'mysql',
operatorsAliases: false, //This gets rid of a sequelize deprecated warning , refer https://github.com/sequelize/sequelize/issues/8417
host: dbhost
});
return connection;
}
exports.setModels = function(connection){
//Import all the known models for the project.
const fs = require('fs');
const dir = __dirname+'/../models';
var models = {}; //empty model object for adding model instances in file loop below.
//#JA - Wait until this function finishes ~ hence readdirSync vs regular readdir which is async
fs.readdirSync(dir).forEach(file => {
console.log(file);
//Split the .js part of the filename
var arr = file.split(".");
var name = arr[0].toLowerCase();
//Create a modle object using the filename as the reference without the .js pointing to a created sequelize instance of the file.
models[name] = connection.import(__dirname + "/../models/"+file);
})
//Showcase the final model.
console.log(models);
return models; //This returns a model with reference to the sequelize models
}
I can't get the create command to work however with this setup. My guess is the variables must not be passing through correctly somehow. I'm not sure what I'm doing wrong?
The create command definitely works because if in the sequelize-lib.js I modify the setModels function to this...
exports.setModels = function(connection){
//Import all the known models for the project.
const fs = require('fs');
const dir = __dirname+'/../models';
var models = {}; //empty model object for adding model instances in file loop below.
//#JA - Wait until this function finishes ~ hence readdirSync vs regular readdir which is async
fs.readdirSync(dir).forEach(file => {
console.log(file);
//Split the .js part of the filename
var arr = file.split(".");
var name = arr[0].toLowerCase();
//Create a modle object using the filename as the reference without the .js pointing to a created sequelize instance of the file.
models[name] = connection.import(__dirname + "/../models/"+file);
models[name].create({
"name":"joe",
"loggedIn":true
});
})
//Showcase the final model.
console.log(models);
return models; //This returns a model with reference to the sequelize models
}
Then it works and I see the item added to the database! (refer to proof image below)
Take note, I am simply running create on the variable at this point. What am I doing wrong where the model object is not passing between files correctly? Weird part is I don't get any errors thrown in the main file?? It's as if everything is defined but empty or something and the command is never run and nothing added to the database.
I tried this in the main file also and no luck.
models["users"].create({
name: 'joe',
loggedIn: true
}).then( task => {
console.log("saved user!!!!!");
});
The purpose of this all is to read models automatically from the model directory and create instances that are ready to go for every model, even if new one's are added in the future.
UPDATE::
So I did another test that was interesting, it seems that the create function won't work in the .then() function of the sync command. It looks like it was passing it correctly though. After changing the front page to this...
var config = require('./libs/sequelize-lib.js');
var connection = config.getSequelizeConnection();//Choosing to not pass in variable this time since this should only run via script.
var models = config.setModels(connection);//Creates live references to the models using connection previosly created.
models["users"].create({
"name":"joe",
"loggedIn":true
});
//Alter table as needed but do NOT force the change. If an error occurs we will fix manually.
connection.sync({ alter: true, force: false }).then(function() {
process.exit();//close the nodeJS Script
}).catch(function(error) {
console.log(error);
});
Doing this seems to get create to work. I'm not sure if this is good form or not though since the database might not be created at this point? I need a way to get it to work in the sync function.
Well I answered my question finally, but I'm not sure I like the answer.
var config = require('./libs/sequelize-lib.js');
var connection = config.getSequelizeConnection();//Choosing to not pass in variable this time since this should only run via script.
var models = config.setModels(connection);//Creates live references to the models using connection previosly created.
//Alter table as needed but do NOT force the change. If an error occurs we will fix manually.
connection.sync({ alter: false, force: false }).then( () => {
models["users"].create({
"name":"joe",
"loggedIn":true
}).then( user => {
console.log("finished, with user.name="+user.name);
process.exit();
}).catch( error => {
console.log("Error Occured");
console.log(error);
});
}).catch(function(error) {
console.log(error);
});
turns out that process.exit was triggering before create would occur because create happens async. This means that all my code will have to constantly be running through callbacks...which seems like a nightmare a bit. I wonder if there is a better way?
I am using following packages for multi-languages solutions.
var i18next = require('i18next');
var i18nFsBackend = require('i18next-node-fs-backend');
var i18nMiddleware = require('i18next-express-middleware');
Since I am using handlebar as my nodejs template engine, that's I can not use i18next t('key') directly in the HTML.
so I created a handlebar helper like following
```javascript
var i18next = require('i18next');
handlebars.registerHelper('t', function(i18n_key) {
console.log(i18next.language)// always undefined, so i18next.t(i18n_key) always return default translation.
var result = i18next.t(i18n_key);
return new handlebars.SafeString(result);
});
```
However, the problem was the function is unable to detect language changed
My Workaround
app.js
```javascript
var i18nextInitCallback = function(error, t){
handlebars.registerHelper('t', function(i18n_key) {
if(app.locals.language !== i18next.language){
i18next.changeLanguage(app.locals.language);
}
var result = i18next.t(i18n_key);
return new handlebars.SafeString(result);
});
};
```
route
```javascript
router.use(function(req, res, next){
res.locals.lng = req.language;
res.app.locals.language = req.language;
next();
});
```
as you can see that on Route I assign res.app.locals.language = req.language;
and then in the handlebar helper function, I use app.locals.language to get the current language and use i18next.changeLanguage() to change the language.
and it worked.
I would like to know if I am doing it right or not?
or if there is a better solution
Using the handle function of the middleware:
app.use(middleware.handle(i18next, {
// options
}));
res.language gets already set for you and a t function fixed to user language of that request.
see: https://github.com/i18next/i18next-express-middleware/blob/master/src/index.js#L48
check out the handlebars sample: https://github.com/i18next/i18next-express-middleware/tree/master/examples/basic-handlebars
This is maddening, how do I get a hold of a loopback model so I can programmatically work with it ? I have a Persisted model named "Notification". I can interact with it using the REST explorer. I want to be able to work with it within the server, i.e. Notification.find(...). I execute app.models() and can see it listed. I have done this:
var Notification = app.models.Notification;
and get a big fat "undefined". I have done this:
var Notification = loopback.Notification;
app.model(Notification);
var Notification = app.models.Notification;
and another big fat "undefined".
Please explain all I have to do to get a hold of a model I have defined using:
slc loopback:model
Thanks in advance
You can use ModelCtor.app.models.OtherModelName to access other models from you custom methods.
/** common/models/product.js **/
module.exports = function(Product) {
Product.createRandomName = function(cb) {
var Randomizer = Product.app.models.Randomizer;
Randomizer.createName(cb);
}
// this will not work as `Product.app` is not set yet
var Randomizer = Product.app.models.Randomizer;
}
/** common/models/randomizer.js **/
module.exports = function(Randomizer) {
Randomizer.createName = function(cb) {
process.nextTick(function() {
cb(null, 'random name');
});
};
}
/** server/model-config.js **/
{
"Product": {
"dataSource": "db"
},
"Randomizer": {
"dataSource": null
}
}
I know this post was here a long time ago. But since I got the same question recent days, here's what I figured out with the latest loopback api:
Loopback 2.19.0(the latest for 12th, July)
API, Get the Application object to which the Model is attached.: http://apidocs.strongloop.com/loopback/#model-getapp
You can get the application which your model was attached as following:
ModelX.js
module.exports = function(ModelX) {
//Example of disable the parent 'find' REST api, and creat a remote method called 'findA'
var isStatic = true;
ModelX.disableRemoteMethod('find', isStatic);
ModelX.findA = function (filter, cb) {
//Get the Application object which the model attached to, and we do what ever we want
ModelX.getApp(function(err, app){
if(err) throw err;
//App object returned in the callback
app.models.OtherModel.OtherMethod({}, function(){
if(err) throw err;
//Do whatever you what with the OtherModel.OtherMethod
//This give you the ability to access OtherModel within ModelX.
//...
});
});
}
//Expose the remote method with settings.
ModelX.remoteMethod(
'findA',
{
description: ["Remote method instaed of parent method from the PersistedModel",
"Can help you to impliment your own business logic"],
http:{path: '/finda', verb: 'get'},
accepts: {arg:'filter',
type:'object',
description: 'Filter defining fields, where, include, order, offset, and limit',
http:{source:'query'}},
returns: {type:'array', root:true}
}
);
};
Looks like I'm not doing well with the code block format here...
Also you should be careful about the timing when this 'getApp' get called, it matters because if you call this method very early when initializing the model, something like 'undefined' error will occur.