I'm using Electron to create a little desktop app and exporting with module.exports. On the 'server' side this works fine. However, when I'm using module.exports on the front end, as per Electron docs, I get this error.
Uncaught TypeError: this.showProgressbar is not a function"
var ViewController = {
getPageCount: function (res) {
this.total = res;
this.showProgressbar(res);
},
showProgressBar: function (num) {
$('.progress-container').addClass('show');
$('.progress-bar').style('width', '0%');
}
};
module.exports = ViewController;
On the client side, this is how I'm accessing this file.
var view = require(__dirname + '/client/ViewController.js');
ipc.on('page_count', view.getPageCount);
How should I be accessing internal methods in this instance?
ViewController is neither a 'Class' nor an instance, its a plain javascript object with two properties.
If you want it to behave like a class and be able to acccess to other properties from a method when creating an instance this is how you should do:
var ViewController = function(ipc){
this.ipc=ipc;
this.ipc.on('page_count', this.getPageCount);
};
ViewController.prototype.getPageCount: function (res) {
this.total = res;
this.showProgressbar(res);
},
ViewController.prototype.showProgressBar: function (num) {
$('.progress-container').addClass('show');
$('.progress-bar').style('width', '0%');
}
module.exports = ViewController;
You still need to instantiante ViewController :
var ViewController = require(__dirname + '/client/ViewController.js');
var controller = new ViewController(ipc);
That's because when the callback is being called, it's being called in the wrong context. To bind the context, use Function.bind.
ipc.on('page_count', view.getPageCount.bind(view));
Related
I have a file called helpers.js in the 'helpers' folder. The contents are like below:
class Helpers {
constructor(config) {
if (this._singleton) {
throw new Error('A singleton has already been created.');
}
this._singleton = this;
}
/**
* Gets the singleton object.
* #returns {Helpers}
*/
static getSingleton() {
return this._singleton;
}
}
module.exports = Helpers;
Then in /helpers/user.js I want to get the helper's singleton instance.
This is my code:
const helpers = require('../helpers').getSingleton();
or
const Helpers = require('../helpers');
const helpers = Helpers.getSingleton();
The error I keep getting is:
TypeError: require(...).getSingleton is not a function
or
TypeError: Helpers.getSingleton is not a function
If I hover over Helpers in VSCode, I get this tooltip
And, whenever I hover over getSingleton() I get this tooltip:
So the path is correct, but it still gives me the errors.
The easiest way to implement the singleton pattern in JavaScript is to just not export the class at all, e.g.
class Helpers {}
let helper;
module.exports = function() {
if (!helper) helpers = new Helpers();
return helper;
};
// loaded with
var helpers = require('../helpers')(); // note the extra () to call it
or even better, since we aren't restricted to Java-like behavior, just skip the function entirely and do
class Helpers {}
module.exports = new Helpers();
// loaded with
var helpers = require('../helpers');
but then if all your module is exporting is a single instance of a class, there's very little reason to use a class in the first place. You might as well do
exports.helperMethodOne = function(){};
exports.helperMethodTwo = function(){};
exports.helperMethodThree = function(){};
// loaded with
var helpers = require('../helpers');
or
module.exports = {
helperMethodOne() {},
helperMethodTwo() {},
helperMethodThree() {},
};
// loaded with
var helpers = require('../helpers');
Your require statement is wrong, but its hard to tell you precisely the right syntax without knowing your environment.
const config = require('/path/to/file');
Is typical. So try:
const Helpers = require('../helpers');
You wrote '../helpers.js' in your screenshot, not '../helpers'
You get the error:
TypeError: require(...).getSingleton is not a function
Because require(...) resolves to something else, like null, and null.getSingleton is not a function.
Also, you cannot reference this meaninfully inside a static context. this ought to only be used for class instances, not static members.
You can do something like this to use it as Singleton.getInstance();
class Singleton {
static instance = new Singleton();
static getInstance = () => Singleton.instance;
constructor() {
throw new Error('Use Singleton.getInstance()');
}
}
module.exports = Singleton;
or even something more sneaky and use it as new Singleton()
class Singleton {
static instance;
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
}
module.exports = Singleton;
I've set up a class with a singleton design like this.
The file is called helpers.js.
class Helpers {
//Code
}
let singleton;
/**
* #returns {Helpers}
*/
const getHelpers = (options) => {
if (!singleton) {
singleton = new Helpers(options);
}
return singleton;
};
module.exports = getHelpers;
That means the first time, I'll have to do
const helpers = require('./helpers')(options);
And every time after, I just have to do:
const helpers = require('./helpers')();
For some reason I keep getting
TypeError: require(...) is not a function
My require requires the right file, and my VSCode autocorrect says that requiring it will give me a function that returns a Helpers, and that require(''')() will return a Helpers.
I have no idea what can be wrong.
EDIT
When I inspect the return value of require('./helpers') it's an object with some basic functions.
In NodeJS world we require modules using require function:
var foo = require ("foo");
In JavaScript (also in NodeJS) we have const keyword that creates a constant:
const
Creates a constant that can be global or local to the function in which it is declared. Constants follow the same scope rules as variables.
Example:
$ node
> const a = 10
undefined
> a
10
> a = 7
7
> a
10
My question is: would it be good to require libraries as constans?
Example:
const foo = require ("foo")
, http = require ("http")
;
/* do something with foo and http */
Are there any bad/good effects using const instead of var when requiring libraries?
It turns out that it became a common practice to use const over var for dependencies. At least in the Node.js source code this is happening:
http.js
So, I guess it's a good practice. I started to use it as well in my modules.
NodeJS hasn't any optimisations for library that requires as const - require is a simple non native function, which nothing is known about the type of the variable to which is assigned. There is source code of require:
Module.prototype.require = function(path) {
assert(util.isString(path), 'path must be a string');
assert(path, 'missing path');
return Module._load(path, this);
};
Module._load = function(request, parent, isMain) {
if (parent) {
debug('Module._load REQUEST ' + (request) + ' parent: ' + parent.id);
}
var filename = Module._resolveFilename(request, parent);
var cachedModule = Module._cache[filename];
if (cachedModule) {
return cachedModule.exports;
}
if (NativeModule.exists(filename)) {
// REPL is a special case, because it needs the real require.
if (filename == 'repl') {
var replModule = new Module('repl');
replModule._compile(NativeModule.getSource('repl'), 'repl.js');
NativeModule._cache.repl = replModule;
return replModule.exports;
}
debug('load native module ' + request);
return NativeModule.require(filename);
}
var module = new Module(filename, parent);
if (isMain) {
process.mainModule = module;
module.id = '.';
}
Module._cache[filename] = module;
var hadException = true;
try {
module.load(filename);
hadException = false;
} finally {
if (hadException) {
delete Module._cache[filename];
}
}
return module.exports;
};
For more time library is an object (I think you don't have library like this module.exports = 10).
You can change all fields of object also if it is declared as const (If you want to get realy const object use Object.freeze(someObject)).
For conclusion: the effect is the same as for a common variable.
Link to V8 Variable Declaration Function used in NodeJS
//lib.js
var opt = 0
exports.set = function(arg) {
opt = arg
}
exports.prn = function() {
console.log(opt)
}
///prog.js
var lib = require('./lib')
var lib2 = require('./lib')
lib.set(222)
lib2.set(333)
lib.prn()
lib2.prn()
prog.js will output:
333
333
but I need it to output:
222
333
In ohter words, opt must be unique to variable lib and to variable lib2. How to achieve that?
That's because normally nodejs caches its modules which are got via require. You may use the following helper:
// RequireUncached.js
module.exports = function(module) {
delete require.cache[require.resolve(module)]
return require(module);
}
and the usage of the helper:
var requireUncached = require('RequireUncached.js');
requireUncached("./lib");
Have in mind that this approach is considered as bad practice and should not be used. I'll suggest to wrap your logic into a function, require the module and call the function. So, every time you get a new instance.
require will not load scripts multiple times, but always yield the same instance.
If you need different environments, make your module a constructor function that allows to be instantiated multiple times. Store opt on each object for that instead of in the (global) module scope.
// lib.js
module.exports = function constr() {
var opt = 0
this.set = function(arg) {
opt = arg
};
this.print = function() {
console.log(opt)
};
};
// prog.js
var lib = require('./lib'),
inst1 = new lib(),
inst2 = new lib();
/* or short:
var inst1 = new require('./lib')(),
inst2 = new require('./lib')(); */
inst1.set(222)
inst2.set(333)
inst1.print()
inst2.print()
The way the NodeJS module system works, the output is correct and your expectations contradict the design principle here.
Each module is loaded once and only once, and subsequent calls to require simply return the reference to the pre-existing module.
Maybe what you need to do is create a class you can create one or more instances of instead of using module-level globals.
Adding to Bergi's answer, You may also try it like
// prog.js
var lib = require('./lib')(),
lib2 = require('./lib')();
lib.set(222)
lib2.set(333)
lib.print()
lib2.print()
// lib.js
module.exports = function constr() {
var opt = 0
return { set : function(arg) {
opt = arg
},
print : function() {
console.log(opt)
}
}
};
Add this line as first line of your lib.js
delete require.cache[__filename]
now your module becomes in a separate namespace each time you require it.
I'm trying to call a public method from within the module pattern.
I'm using the module pattern because it allows for splitting into various different JS files, to make the code more organised.
However when I call the public method, I get a TypeError and also typeof remains undefined.
Please help!! Thanks in advance.
main.js
function MainObject() {
this.notify = function(msg) { console.log(msg); }
}
var connObj = require("./myextobj");
var mainObj = new MainObject();
connObj.connection.handle = mainObj;
console.log(typeof connObj.connection.connect); // undefined
connObj.connection.connect(); // TypeError: Object has no method 'connect'
myextobj.js
module.exports = {
connection: function () {
this.handle = eventhandle;
this.connect = function() {
// connect to server
handle.notify("completed connection....");
}
}
}
It's because you're exporting an object containing connection: function (), which is a constructor function and needs newing-up. Then you can access the this properties attached to that particular instance:
var connection = require("./myextobj").connection; // reference the constructor function
var conn = new connection(); // new-up connection
console.log(typeof conn.connect); // -> function
Edit:
If the only thing exported by myextobj.js is the constructor function, there's no need to wrap it up in a literal object. I.e. you could do:
module.exports = function Connection() {
this.handle = eventhandle;
this.connect = function() {
handle.notify("completed connection....");
}
}
then use like so:
var Connection = require("./myextobj");
Note: .connection is no longer appended to the end to reference the function.
Give this a shot.
var module = {};
module.exports = {
connection: function () {
return {
handle: eventhandle,
connect: function () {
// connect to server
handle.notify("completed connection....");
}
}
}()
}
module.exports.connection.connect()