How to Call Method of ModelB.js from within ModelA.js? - javascript

I am working with loopback 2.0.
I generated my models with the yeoman generator and added a js file for each model to extend its behavior.
How can I call a method from ModelA within ModelB?
EXAMPLE
Folder structure:
/common
/models
Car.json
Car.js
Engine.json
Engine.js
...
Car.js:
module.exports = function(Car) {
Car.drive = function(destination, fn) { ... }
...
};
Engine.js:
module.exports = function(Engine) {
Engine.doSomething = function(something, fn) {
// *** Here is where I want to invoke a method from the Car.js
var loopback = require('loopback');
var Car = loopback.models.Car;
Car.drive('49.1234,12.1234', fn);
// ***
}
...
};

The model class such as Engine will have a property app to provide access to other models, for example:
module.exports = function(Engine) {
Engine.doSomething = function(something, fn) {
// *** Here is where I want to invoke a method from the Car.js
var Car = Engine.app.models.Car;
Car.drive('49.1234,12.1234', fn);
// ***
}
...
};

Related

Is there a better way to implement a singleton pattern, using Node.js?

I'm working on a (pseudo) game engine to be used with Foundry.js. The intention was to create a scaffolding that can be reused to quickly create different game systems. To make the final product easier to read and troubleshoot, I decided to use Node.js and a very modular system. (I'm not sure if any more context is needed, but please ask if it is.)
Is there any obvious issue with my implementation?
Note: I'm an 2nd year medical student and self-taught over the past summer --> a lot of what I do might look weird so...
Note: the file and object names were removed, along with extemporaneous code. I added some fillers so that the general idea would still be conveyed
core file: singleton which contains all engine modules within its instance
const Module_A = requires('./modules/module_a.js');
const Module_B = requires('./modules/module_b.js')
module.exports = (function(){
var instance;
function createInstance(){
var o = Object.create({
Module_A: Module_A,
Module_B: Module_B,
// etc.
})
return o;
}
return {
getInstance: function(){
if(!instance){
instance = createInstance();
}
return instance;
},
Module_A: function(){
if(!instance){
instance = createInstance();
}
return instance.Module_A;
},
Module_B: function(){
if(!instan ce){
instance = createInstance();
}
return instance.Module_B;
}
};
}())
an abstract class declaration
module.exports = (
class {
constructor(){}
static getType = function(){
return entityConfig.type;
};
static entityConfig = {
type: 'Object.(Engine.Entity)'
}
}
);
a concrete class declaration
const Entity = requires('*./entity.js');
module.exports = (
class extends Entity {
static requiredParameters = () => {throw `incomplete code at ${new Error().lineNumber}`};
static optionalParameters = () => {throw `incomplete code at ${new Error().lineNumber}`};
static docData = () => {throw `incomplete code at ${new Error().lineNumber}`};
/* ------------------------------------ */
/* CONSTRUCTOR */
/* ------------------------------------ */
constructor(){
arguments.forEach(arg => {
if(!arg.includes(requiredParameters) && !arg.includes(optionalParameters)){
throw console.error(`ERROR: unknown token; ${arg}\n${docData}`);
}
});
this._data = args.data;
this.data = this._data;
}
}
);

Is a Node.js module a singleton?

I used to implement singleton this way:
class MySomething {
constructor(props) {}
}
let myInstance = null;
module.exports = (props) => {
//first time call
if(props) {
myInstance = new MySomething (props);
return myInstance;
} else {
return myInstance;
}
this assumes that at app.js (entry file) I will call first:
require('./MySomething')(props)
then everywhere in the project I use:
const instanceOfSomething = require('./MySomething')();
I discovered that every time I got a new instance!
What's wrong in my code?
I tried also this way:
class MySomething {...}
const mySomething = (function() {
let myInstance = null;
return {
init: function() {
myInstance = new MySomething();
},
getInstance: function() {
return myInstance ;
}
}
})();
module.exports = mySomething;
and I got the some problem when importing this module from different files, anyone can explain to me?
every require of file create new instance of mySomething
UPDATE
I tried this example now:
class MySomething {...}
const mySomething = {
myInstance: null,
init: function() {
myInstance = new MySomething();
},
getInstance: function() {
return myInstance ;
}
}
};
module.exports = mySomething;
The same problem happened, maybe it is related to my project structure, I will explain it here:
the code below belongs to module "facts"
facts folder contains a folder named "dao" this folder contains MySomething.js (the singleton)
in the facts/index.js I have:
const Localstorage = require('./dao/MySomething');
exports.init = (path) => {
Localstorage.init(path)
}
exports.Localstorage = Localstorage;
Now in a folder named "core" which contains the "facts" folder I re-exported the Localstorage again in "index.js" like this:
const facstModule = require('./facts');
exports.Localstorage = facstModule.Localstorage;
Then in "schedule" folder which contains "Runtime.js" within I write:
const { Localstorage } = require('../core');
setTimeout(() => {
const localstorageIns = Localstorage.getInstance(); //this is always null!
}, 5000)
In app.js file (entry point) I did:
const facts = require('./src/facts');
facts.init(__dirname);
Normally instance will be created before the timeout execute the callaback,
But I noticed that there two instance of Localstorage which is singleton
the cleanest way to do a singleton is
class MyClass () { ... }
module.exports = new MyClass()
if you need a singleton that gets instantiated once, I would do:
class MyClass () { ... }
let myClass
const MyClassSingleton = (...args) => {
if (myClass) {
return myClass
}
myClass = new MyClass(...args)
return myClass
}
module.exports = MyClassSingleton
Every require of file create new instance of mySomething because every time you return new object with init method and getInstance method.
If you need singleton you need do like this:
class MySomething {
constructor() {
if (!MySomething.instance) {
MySomething.instance = this;
}
}
getInstance: function() {
return MySomething.instance;
}
}
module.exports = MySomething;
class Singleton {
constructor() {
this.my_obj;
}
static makeObject() {
if (!this.my_obj) {
this.my_obj = new Singleton();
}
return this.my_obj;
}
add() {
return 1
}
}
// so to get the object we need to call the makeobject method
const obj = Singleton.makeObject()
console.log(obj.add());

Calling an object in main.js from a module in Electron

I have an Electron app with 2 modules, one of them being the standard Menu. When I click a menu item, I want it to call an instantiated module's function.
The only solution I've found is to have my instantiated object being a property of the main electron.app object, which is globally available.
Here's my example:
main.js
const electron = require('electron');
const app = electron.app;
const WindowManager = require('components/WindowManager');
let windowManager = new WindowManager(); // <- I want my menu item to call a function from this object
const MainMenu = require('components/MainMenu');
let mainMenu = new MainMenu();
function initApp() {
let menuTemplate = mainMenu.getTemplate();
let menuBuilt = electron.Menu.buildFromTemplate(menuTemplate);
electron.Menu.setApplicationMenu(menuBuilt);
}
function mainTestFileOpen() {
console.log('File open test function in main.js');
}
// I'm trying to avoid doing this
app.testFileOpen = function() {
console.log('Function is part of "app" so globally accessible...');
}
// I'm trying to avoid doing this too
app.appWindowManager = new WindowManager();
// Start the app
app.on('ready', initApp);
components/WindowManager.js
class WindowManager {
constructor() {
this.doFileOpen = this.doFileOpen.bind(this);
}
doFileOpen() {
console.log('File open from WinwdowManager module');
}
}
module.exports = WindowManager;
components/MainMenu.js
const electron = require('electron');
class MainMenu {
constructor() {
this.template = [];
this.init = this.init.bind(this);
this.getTemplate = this.getTemplate.bind(this);
// Initialize
this.init();
}
getTemplate() {
return this.template;
}
init() {
this.template = [{
label: 'File',
submenu: [{
label: "Open File",
click() {
/** Calling a function in main.js does NOT work **/
mainTestFileOpen();
/** Calling an object in main.js doe NOT work **/
windowManager.doFileOpen();
/** If the function is part of "app" then it works **/
electron.app.testFileOpen();
/** If the instantiated object is part of "app" then it works **/
electron.app.appWindowManager.doFileOpen();
}
}]
}]
}
}
module.exports = MainMenu;
I think what I am not getting is the scope of click() in an Electron Menu template.
You're trying to call a function from a different module (every file in Node is its own module, which is different from the typical JS environment) without first importing the module.
It's not enough to just write a function in the main.js module:
function mainTestFileOpen() {
console.log('File open test function in main.js');
}
And expect to call it from the MainMenu.js module. You must first export it:
export function mainTestFileOpen() { ... }
Then, in MainMenu.js, you can import it at the top:
import { mainTestFileOpen } from "../main";
Same thing with windowManager. It doesn't look like you're doing anything with WindowManager from main.js, so just move the import and instantiation to MainMenu.js:
import { WindowManager } from "./WindowManager";
let windowManager = new WindowManager();
And then you'll be able to do:
windowManager.doFileOpen();
Side Note:
You do stuff like this in your constructor: this.doFileOpen = this.doFileOpen.bind(this);
There is no need for this as the only way somebody could call doFileOpen is by calling it on the windowManager instance like so: windowManager.doFileOpen(...).
The same applies to:
this.init = this.init.bind(this);
this.getTemplate = this.getTemplate.bind(this);

Is there a more elegant way to "fake" class inheritance?

I have not found an easy way to extend Mongoose Schema/Model methods because of the way that mongoose handles them, and because of the fact that mongoose=require('mongoose') is a singelton.
So, I am 'faking' class inheritance here:
'use strict';
var _ = require('lodash');
module.exports = function(MongooseModel, options) {
var Collection = {};
_.assign(Collection, _.toPlainObject(MongooseModel));
Collection.pluralName = Collection.modelName + 's';
Collection.foo = Collection.bar;
return Collection
};
Does anyone have a more elegant solution?
EDIT:
Turns out the above solution doesn't work. For instance, using Collection.find({}, function(err, docs) {...}) will error when Mongo tries to create "docs" from a model that has not been registered with Mongoose.
So, what I've done is now completely inelegant:
'use strict';
var _ = require('lodash');
module.exports = function(MongooseModel, options) {
var Collection = MongooseModel;
...
return Collection
};
There are some ways to try and do this, though not sure exactly what your trying to extend.
You can add instance methods <schema>.methods.<mymethod> = function(){}
// define a schema
var animalSchema = new Schema({ name: String, type: String });
// assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function (cb) {
return this.model('Animal').find({ type: this.type }, cb);
}
And you can add static methods <schema>.statics.<mymethod> = function(){}
// assign a function to the "statics" object of our animalSchema
animalSchema.statics.findByName = function (name, cb) {
return this.find({ name: new RegExp(name, 'i') }, cb);
}
var Animal = mongoose.model('Animal', animalSchema);
Animal.findByName('fido', function (err, animals) {
console.log(animals);
});
Examples are from the mongoose docs - just search for "statics".
The statics functions you can call on a model. The methods are usually functions that work with an instance of a document returned from a query or created with new.

Node JS call a "local" function within module.exports

How do you call a function from within another function in a module.exports declaration?
I have MVC structure node js project and a controller called TestController.js. I want to access method within controller, but using this keyword gives below error:
cannot call method getName of undefined
"use strict"
module.exports = {
myName : function(req, res, next) {
// accessing method within controller
this.getName(data);
},
getName : function(data) {
// code
}
}
How do I access methods within controller?
I found the solution :-)
"use strict"
var self = module.exports = {
myName : function(req, res, next) {
// accessing method within controller
self.getName(data);
},
getName : function(data) {
// code
}
}
You can access the getName function trough module.exports. Like so:
"use strict"
module.exports = {
myName : function(req, res, next) {
// accessing method within controller
module.exports.getName(data);
},
getName : function(data) {
// code
}
}
Maybe you could do it like this. It reduce nesting. And all your export is done at the end of your file.
"use strict";
var _getName = function() {
return 'john';
};
var _myName = function() {
return _getName();
};
module.exports = {
getName : _getName,
myName : _myName
};
If you want to use the function locally AND in other files...
function myFunc(){
return 'got it'
}
module.exports.myFunc = myFunc;
I know the answer is already accepted, but I feel the need to add my two cents on the issue.
Node modules have a "Singletonic" nature, when inside the module, you are the module.
In my opinion, at least design pattern wise, inner module methods can be accessed more cleanly, without the need for this or a copy of self for that matter.
Using this, could be dangerous, if one happens to send the separate methods around and forgets to use .bind.
Using a copy of self, is redundant, we already are inside a Singleton behaving module, why keep a reference to yourself when you can avoid that?
Consider these instead:
Option 1
// using "exports."
exports.utilityMethod = (..args) => {
// do stuff with args
}
exports.doSomething = (someParam) => {
// this always refers to the module
// no matter what context you are in
exports.utility(someParam)
}
Option 2
// using module.exports
const utility = (..args) => {
// do stuff with args
}
const doSomething = (someParam) => {
// Inside the module, the utility method is available
// to all members
utility(someParam)
}
// either this
module.exports = {
utility,
doSomething,
}
// or
module.exports = {
customNameForUtility: utility,
customNameForDoSomething: doSomething
}
This works the same for es6 modules:
Option 1 (ES6)
export const utilityMethod = (..args) => {
// do stuff with args
}
export const doSomething = (someParam) => {
// this always refers to the module
// no matter what context you are in
utility(someParam)
}
Option 2 (ES6)
const utility = (..args) => {
// do stuff with args
}
const doSomething = (someParam) => {
// Inside the module, the utility method is available
// to all members
utility(someParam)
}
export default {
doSomething,
utility
}
// or
export {
doSomething,
utility
}
Again, this is just an opinion, but it looks cleaner, and is more consistent across different implementations, and not a single this/self is used.

Categories

Resources