Node.js use variable from module - javascript

I have app.js
var List = {};
var Entity = require('./entity.js');
var main = new Entity(); // should be changed List
console.log(List) // still empty
and entity.js
class Entity {
constructor(){
this.id = Math.random();
List[this.id] = this; // List == undefined
}
}
module.exports = Entity;
How can I use List as global variable?

Just import List in entity.js:
At the end of app.js:
module.exports = List;
At the start of entity.js:
const List = require('./app.js');
If your app.js needs to export something else as well, then export an object with a List property instead:
At the end of app.js:
module.exports.List = List;
At the start of entity.js:
const List = require('./app.js').List;
You could also consider putting List into its own module that both app.js and entity.js import.
Don't make List a global variable, if at all possible - work with the module system instead, explicit dependencies without global pollution is one of a module system's big advantages.

You need to pass List param and access in constructor ...
new Entity(List);
constructor(List){
...

Related

how to use a global variable when it takes a value in another file

I have a file called app.js:
let id = 0;
const Func = require('./func.js');
Func.myFunc();
console.log(id);
module.exports = {
id
};
Also I have another file called func.js:
const App = require('./app.js');
var myFunc = () => {
App.id = 100;
}
module.exports = {
myFunc
};
But console.log(id) returns: 0
What you are doing is termed circular dependencies. It is generally frowned upon and there is no allowed instance where this may be required. You're better off creating a third file that will use both of them...
Read this to have a better understanding:
https://nodejs.org/api/modules.html#modules_cycles
How to deal with cyclic dependencies in Node.js
Add another log like:
// app.js ...
console.log(module.exports);
module.exports = { id };
console.log(id);
to see that your code does work somehow, in the way that module.exports has an id property set, but you override that afterwards. Also the property of the export object has nothing todo with the id variable (well, the later gets copied into the first) so console.log will never log 100.
There are two problems with your piece of code:
the circular dependency
module.exports.id is not the same object as the variable id in app.js
In order to solve the first problem, you should create a third file where the variable will be declared and other modules will use that.
Now, to illustrate the second problem, look at the following.
// testModule.js
let variable = 0;
function get_variable() {
return variable;
}
module.exports = {variable, get_variable};
// app.js
const testModule = require('./testModule.js');
testModule.variable = 1234;
console.log(testModule.variable); // will print '1234'
console.log(testModule.get_variable()); // will print '0'
This little misunderstanding of modules, could lead to subtle nasty bugs. I consider that the best practice to solve this would be not to export the 'variable' property directly, but having getter/setter functions in the module, almost like transforming it into a class-like thing.
// testModule.js
let variable = 0;
function get_variable() {
return variable;
}
function set_variable(value) {
variable = value;
}
module.exports = {get_variable, set_variable};

Dynamically updating exports Nodejs

I have this object that is being exported and imported by other files. Initially, the object is empty but during an event change ( a button clicked), the object is filled with keys and values but still remains empty in the files that imported it. How can I dynamically update an object and then export it with it's new values.
The code looks something like this:
firstFile.js
const anObject = {};
function clicked() {
anObject.firstName = "John";
anObject.lastName = "Doe" ;
}
module.exports = anObject;
secondFile.js
const importedObject = require("./firstFile");
console.log(importedObject) // always returns an empty object
You have to export and call the clicked function. Otherwise you are never actually updating that object.
For example.
firstFile.js
const anObject = {};
function clicked() {
anObject.firstName = "John";
anObject.lastName = "Doe" ;
}
module.exports = anObject;
module.exports.clicked = clicked;
secondFile.js
const importedObject = require("./firstFile");
console.log(importedObject.firstName) //undefined
importedObject.clicked()
console.log(importedObject.firstName) //John
Edit
After discussing further with the OP this is an Electron application. The code above works in Node.js. Electron might have a different setup and require extra steps to make this work.

Proper way to chain require

I am new to node and npm so thanks for bearing with me here.
I want to package/modularize a series of classes(in separate files) that inherit from a base class and all classes should be visible to the end user/programmer. In other words I want to preserve the previous requires so that I have a master object the end user can require to get everything. require('Event') also requires Item for the user/programmer.
"use strict";
const Item = require('./Item');
module.exports = class Event extends Item {
constructor() {
super();
this.TypeName = 'Event';
this.JSON = '{}';
}
static Bind(service, eventId) {
return new Event();
}
}
and
"use strict";
module.exports = class Item {
constructor() {
this.TypeName = 'Item';
this.JSON = '{}';
}
static Bind(service, itemId) {
return new Item();
}
}
Thanks for your help!
If you want to export multiple things from a a module, then you export a parent object and each of the things you want to export is a property on that object. This is not "chaining" as there really isn't such a thing for exporting multiple top level items from a module.
module.exports = {
Event, Item
};
class Item {
constructor() {
this.TypeName = 'Item';
this.JSON = '{}';
}
static Bind(service, itemId) {
return new Item();
}
}
class Event extends Item {
constructor() {
super();
this.TypeName = 'Event';
this.JSON = '{}';
}
static Bind(service, eventId) {
return new Event();
}
}
Then, someone using this module would do:
const m = require('myModule');
let item1 = new m.Item();
let event1 = new m.Event();
Or, you can assign them to top level variables within the module:
const {Item, Event} = require('myModule');
let item1 = new Item();
let event1 = new Event();
If you have multiple classes each in their own file and you want to be able to load them all with one require() statement, then you can create a master file that does a require() on each of the individual files and combines them into one exported object. Then, when you want to import all of them, you can just require in the master file.
node.js modules are designed such that you require() in everything you need in that module and you do that in each module that wants to use something. This enhances reusability or shareability of modules because each module independently imports the things it needs. You don't have all this global state that has to be imported somewhere before any of the other modules work. Instead, each module is self-describing. It also makes it much more obvious to people working on a module what it depends on because there's a require() statement for everything it depends upon. This may seem like a bit of extra typing for people coming from different environments where you might just import something once into a global namespace (and it is more typing), but there are very good reasons it is done this way and honestly, it doesn't take long to get used to it and then you can enjoy some of the benefits to doing it this way.

node.js/javascript - how to map a variable in a relative path

I have a setFilelocation and I'm using this variable in multiple .js files. So the same path is set every time I use this variable.
Is there any way I can use this variable as a global variable and I can hardcode this location only once, such as:
var setFileLocation = '/home/name/parent1/parentdirec/direc/qa.json';
As you are using node you can use require
I do this with config info like this
in one file called config.js for example
module.exports = {
v1: somevalue,
fileLocation: "/default/file/loc",
computePath: (dir, subdir, file) {
//use Vasans example here
}
};
Then in your code require config.js
var config = require('./config.js');
And you will have access to the variable or the funtion to create the path, whichever way you want
Have a global function instead which will take these inputs and return the full path.
var path = require('path')
function computePath(dir, subdir, file) {
var pathParts = [];
pathParts.push(dir, subdir, file);
return pathParts.join(path.sep);
}
Set it as a global variable:
global.setFileLocation = '/home/name/parent1/parentdirec/direc/qa.json';
Then you can use it in any place of your code:
console.log(setFileLocation);
But remember that using global variable like that is not recommended.
there are many options
using global (not suggest because in the practise, node.js app should not contain global variable)
global.setFileLocation = '/home/name/parent1/parentdirec/direc/qa.json';
export to utility module and import it
==== YOUR_APP/config.js ====
module.exports = {
fileLocation: "/home/name/parent1/parentdirec/direc/qa.json"
};
=== YOUR_APP/SOME_PATH/a.js ====
require('rootpath')();
var config = require('/config')
// config.fileLocation

Share variables between files in Node.js?

Here are 2 files:
// main.js
require('./module');
console.log(name); // prints "foobar"
// module.js
name = "foobar";
When I don't have "var" it works. But when I have:
// module.js
var name = "foobar";
name will be undefined in main.js.
I have heard that global variables are bad and you better use "var" before the references. But is this a case where global variables are good?
Global variables are almost never a good thing (maybe an exception or two out there...). In this case, it looks like you really just want to export your "name" variable. E.g.,
// module.js
var name = "foobar";
// export it
exports.name = name;
Then, in main.js...
//main.js
// get a reference to your required module
var myModule = require('./module');
// name is a member of myModule due to the export above
var name = myModule.name;
I'm unable to find an scenario where a global var is the best option, of course you can have one, but take a look at these examples and you may find a better way to accomplish the same:
Scenario 1: Put the stuff in config files
You need some value that it's the same across the application, but it changes depending on the environment (production, dev or test), the mailer type as example, you'd need:
// File: config/environments/production.json
{
"mailerType": "SMTP",
"mailerConfig": {
"service": "Gmail",
....
}
and
// File: config/environments/test.json
{
"mailerType": "Stub",
"mailerConfig": {
"error": false
}
}
(make a similar config for dev too)
To decide which config will be loaded make a main config file (this will be used all over the application)
// File: config/config.js
var _ = require('underscore');
module.exports = _.extend(
require(__dirname + '/../config/environments/' + process.env.NODE_ENV + '.json') || {});
And now you can get the data like this:
// File: server.js
...
var config = require('./config/config');
...
mailer.setTransport(nodemailer.createTransport(config.mailerType, config.mailerConfig));
Scenario 2: Use a constants file
// File: constants.js
module.exports = {
appName: 'My neat app',
currentAPIVersion: 3
};
And use it this way
// File: config/routes.js
var constants = require('../constants');
module.exports = function(app, passport, auth) {
var apiroot = '/api/v' + constants.currentAPIVersion;
...
app.post(apiroot + '/users', users.create);
...
Scenario 3: Use a helper function to get/set the data
Not a big fan of this one, but at least you can track the use of the 'name' (citing the OP's example) and put validations in place.
// File: helpers/nameHelper.js
var _name = 'I shall not be null'
exports.getName = function() {
return _name;
};
exports.setName = function(name) {
//validate the name...
_name = name;
};
And use it
// File: controllers/users.js
var nameHelper = require('../helpers/nameHelper.js');
exports.create = function(req, res, next) {
var user = new User();
user.name = req.body.name || nameHelper.getName();
...
There could be a use case when there is no other solution than having a global var, but usually you can share the data in your app using one of these scenarios, if you are starting to use node.js (as I was sometime ago) try to organize the way you handle the data over there because it can get messy really quick.
If we need to share multiple variables use the below format
//module.js
let name='foobar';
let city='xyz';
let company='companyName';
module.exports={
name,
city,
company
}
Usage
// main.js
require('./modules');
console.log(name); // print 'foobar'
Save any variable that want to be shared as one object. Then pass it to loaded module so it could access the variable through object reference..
// main.js
var myModule = require('./module.js');
var shares = {value:123};
// Initialize module and pass the shareable object
myModule.init(shares);
// The value was changed from init2 on the other file
console.log(shares.value); // 789
On the other file..
// module.js
var shared = null;
function init2(){
console.log(shared.value); // 123
shared.value = 789;
}
module.exports = {
init:function(obj){
// Save the shared object on current module
shared = obj;
// Call something outside
init2();
}
}
a variable declared with or without the var keyword got attached to the global object. This is the basis for creating global variables in Node by declaring variables without the var keyword. While variables declared with the var keyword remain local to a module.
see this article for further understanding - https://www.hacksparrow.com/global-variables-in-node-js.html
Not a new approach but a bit optimized. Create a file with global variables and share them by export and require. In this example, Getter and Setter are more dynamic and global variables can be readonly. To define more globals, just add them to globals object.
global.js
const globals = {
myGlobal: {
value: 'can be anytype: String, Array, Object, ...'
},
aReadonlyGlobal: {
value: 'this value is readonly',
protected: true
},
dbConnection: {
value: 'mongoClient.db("database")'
},
myHelperFunction: {
value: function() { console.log('do help') }
},
}
exports.get = function(global) {
// return variable or false if not exists
return globals[global] && globals[global].value ? globals[global].value : false;
};
exports.set = function(global, value) {
// exists and is protected: return false
if (globals[global] && globals[global].protected && globals[global].protected === true)
return false;
// set global and return true
globals[global] = { value: value };
return true;
};
examples to get and set in any-other-file.js
const globals = require('./globals');
console.log(globals.get('myGlobal'));
// output: can be anytype: String, Array, Object, ...
globals.get('myHelperFunction')();
// output: do help
let myHelperFunction = globals.get('myHelperFunction');
myHelperFunction();
// output: do help
console.log(globals.set('myGlobal', 'my new value'));
// output: true
console.log(globals.get('myGlobal'));
// output: my new value
console.log(globals.set('aReadonlyGlobal', 'this shall not work'));
// output: false
console.log(globals.get('aReadonlyGlobal'));
// output: this value is readonly
console.log(globals.get('notExistingGlobal'));
// output: false
With a different opinion, I think the global variables might be the best choice if you are going to publish your code to npm, cuz you cannot be sure that all packages are using the same release of your code. So if you use a file for exporting a singleton object, it will cause issues here.
You can choose global, require.main or any other objects which are shared across files.
Otherwise, install your package as an optional dependency package can avoid this problem.
Please tell me if there are some better solutions.
If the target is the browser (by bundling Node code via Parcel.js or similar), you can simply set properties on the window object, and they become global variables:
window.variableToMakeGlobal = value;
Then you can access this variable from all modules (and more generally, from any Javascript context).

Categories

Resources