Access class inside function - node.js

I have a ready() function which contain an es6 class.
I would like to instantiate this class outside the function, however I didn't succeed in making this working.
I don't want to use return function because the function can have more than one class.
Here is an example of what i want to do :
function ready(api) {
class A extends api.C {
contructor() {
this.foo = "bar";
}
}
class B extends A {
contructor() {
this.bar = "foo";
}
}
}
let classA = ready.A; // Here is the problem : I would like to access to the class prototype
The reason is my application have some plugins using remi npm package, and I want to export classes shared between all plugins.
I don't know if it's possible, anybody have an idea ?
[EDIT] :
First thanks all for your hep, In fact I need to be more accurate in my issue.
That's true, I can return back both classes through a classic return. But let me explain what I want to do exactly :
I have a core application which have some plugins. Plugins can be internally integrated to core, or through a classic NPM install. As explained above I use remi plugin loader.
The desired rules are the following : Each plugin get a core API access through a callback. Each plugin can expose classes to be used in other plugins. Each plugins can have inheritance for those exposed (ie exported) plugins.
Here is how I describe a plugin :
/**
* This class is a sample plugin
* #class
*/
class Sample {
constructor(api) {
this.api = api;
}
/**
* Shows a test log
*/
test() {
console.log("======> I'm working !");
}
}
function loaded(api) {
let s = new Sample(api);
}
module.exports = (api, options) => {
};
module.exports.attributes = {
loadedCallback: loaded,
name: "sample-plugin",
version: "0.0.0",
category: "misc",
description: "I'm a sample plugin",
classes: [Sample]
};
The core plugin manager will load the first time all plugins, and will register into an array all classes protoypes exported into the classes attributes property.
Then the loaded(api) function is called and classes can be instantiated through api.classes object.
In another plugin, I can do this :
function loaded(api) {
let sample = new api.classes.Sample(api);
}
And I can instantiate a class described in another plugin.
That's the idea.
However I would like to do a more complex API usage with the multiple inheritance, for example :
Plugin A exposes class A
Plugin B exposes class B extends A
Plugin C exposes class C extends B
To be more clear, I would like to export globally some classes, to get a shared access between NPM modules

You can return class A from ready function, so after calling ready you can access A class
function ready(api) {
class A extends api.C {
contructor() {
this.foo = "bar";
}
}
class B extends A {
contructor() {
this.bar = "foo";
}
}
return {A : A};
}
let classA = ready(api).A;

Related

Awilix: Unable to resolve subclass with hard coded base class constructor parameters

I use the awilix library for achieving DI in my nodejs express project which used ES6 and nodejs 12.x.
Let's say I have a base class and a subclass as follows
class MyBaseClass {
#collectionName;
constructor(collectionName) {
this.#collectionName = collectionName;
}
getCollection() {
return this.#collection;
}
}
class MySubClass extends MyBaseClass {
constructor() {
super("users");
}
}
I use awilix.InjectionMode.CLASSIC. When I try to resolve and instance of MySubClass, I get a resolution error which basically says "Could not resolve 'collectionName'". MySubClass does not need constructor parameters to be passed in order to be instantiated. What am I doing wrong?

How to use class functions in another class?

How can i use class instance in another class like a pointer in C++ to class instance functions?
Example:
class A {
constructor()
{
this.block = [];
}
method()
{
return this.blocks.length;
}
}
another class:
class B {
constructor(instance)
{
this.instance = instance;
}
method()
{
this.instance.method(); // here i'm getting cannot get length of undefined
}
}
If i'm trying to to like that i'm getting problems to call it
You can try this. Here, when creating B class's instance I give into it an A class's instance as argument. Then inside B we can call A instance's methods, and access its properties.
Also, as #ViaTech posted you can use static methods to access them without needing to initialize an object of the class. That is what static methods is. Refer Static Methods
class B {
constructor(instance)
{
this.instance = instance;
}
method()
{
this.instance.method();
}
}
class A {
constructor()
{
}
method()
{
console.log("A's method");
}
}
var a = new A();
var b = new B(a);
b.method(); // A's method
You can easily do this in JS by calling a static method like so:
class A {
static write(){ //static method
console.log("Called write from A");
}
}
class B {
doIt(){
A.write();
}
}
let b = new B();
b.doIt();
Option 2, you instantiate the class in the constructor of the other like so:
class A {
write(){
console.log("Non-static write() called from class A");
}
}
class B {
constructor() {
this.a = new A();
}
doIt(){
this.a.write();
}
}
let b = new B();
b.doIt();
There are a few ways:
I accidentally switched between PHP and Javascript, but the principles are the same for both)
Use static functions:
Normally, you have a this in the class. Say you have this code:
class Car {
let color;
public function setColor(newColor){ this.color = newColor;}
}
let car = new Car();
car->setColor('green')`
The setColor function's this refers to that car. You can make let anotherCar = new Car(), then when you do anotherCar->setColor('red') you only change that car, not the first one. Simplistic: You can create multiple instances.
If you do not need that, but need the class once, you can make it static. A simple way to explain would be "you have a collection of seperate functions, just put into a wrapping class (which doesn't do a lot really)". For instance, you might have some sanatizing methods:
class Sanitize {
static function makeHtmlSave(input){
return doYourMagicHere(input);
}
static function removeXssCode(input){
return doMoreMagicHere(input);
}
}
This way, you can reuse it multiple times. If you want to use it, you do Sanitize::makeHtmlSave(someCode) where you need it. There isn't a Sanitize thing, it's just a wrapper to access the frunctions inside it.
Use extend:
You can extend a class. Say you have a generic class Vehicle, which has some properties (eg a motor, numberWeels, color) and you can extend that with more specific classes:
class Vehicle {
let color;
public function setColor(newColor){ this.color = newColor}
}
class Car extends Vehicle {
let hasAirco = false;
public function hasAirco(newValue){ this.hasAirco = newValue};
}
If you do let car = new Car(), you get a Car object, that extends/enlarges/complements the Vehicle class, so you can use both its (public) functions. Internally, Car can use the functions of Vehicle too.
Just pass it
class One {
// some stuff
}
class Two{
let otherObject;
construct(givenObject){
this.otherObject = givenObject;
}
}
You can now do this let a = new One(); let b = new Two(a);. You can not use the functions of One inside Two, but you can still use a->doSomething(). This solution feels like the easiest, but it almost never is. Classes/objects are tricky stuff, but I've rarely uses this solutions. There are use cases, but often it's a bad smell indicator.

How to make Module Functions access a Class context in node.js

I am trying to use a more object oriented approach with node.js "embedding" functions ( if that is the right word ) so that I can use functions and objects as if they are in the objects context. It might be easier to show in code.
I realise you can assign individual functions in the constructor - and this would work.. but I am not sure how to assign a whole module with functions to all the functions can access values in the objects context.
So , my question is : How can I assign a module to a class so that all the functions within the module can access everything within the objects context.
app.js
const myFunctions = require('./functions');
class myClass{
constructor() {
this.myFunctions = myFunctions ;
}
}
var mc = new myClass();
mc.myObject = { aaa: 'test'}
mc.myFunctions.outputValue(); // << should output the previous value set.
functions.js
function outputValue(){
console.log(this.myObject)
}
module.exports = {
outputValue
}
You could do it in two ways:
1 - Bound your class instance this to each one of the external functions:
class myClass {
constructor() {
this.myFunctions = {
outputValue: myFunctions.outputValue.bind(this),
};
}
}
2 - Define a method in your class to call the external functions, like:
class myClass {
constructor() {
}
callFunction(fnName) {
const fn = myFunctions[fnName];
if (fn) fn.apply(this);
}
}
Said that I will recommend avoiding using classes and this at all (at least it's completely necessary) and instead use pure functions, functions that only receive parameters does some processing and return some value.
The best way to do this which also follows the injection pattern,
const myClass = new myClass(myFunctions);
myClass.outputValue.bind(myClass);
Here it binds and inject all the class objects so it is accessible to other methods in different class .
Note : Look at "bind" usage.

inherited class can not use the variable defined in the base class in node.js ES6 styled class ?

I am using ES6 syntax style to make the inheritance class in node.js, there is two classes, in which the base class is to build a mqtt client, and the inherited class is to extend the base class.
However, the problem is the inherited class can not use the variable defined in the base class.
For example, in my base class, there is a public variable called : this.mqtt_client, when I tried to use this variable in the inherited class, it always gives a undefined issue
My base class is as followed
var mqtt = require('mqtt'),
EventEmitter = require('events').EventEmitter;
class MQTTBaseClass extends EventEmitter{
constructor( option) {
super();
this.mqtt_client = null;
this.uri = option.uri;
this.mqttOptions.clientId = option.clientId;
}
init(uri, mqttOptions){
this.mqtt_client = mqtt.connect( uri , mqttOptions );
this.mqtt_client.on('connect', onConnectionSuccess);
this.mqtt_client.on('error',onConnectionError);
this.mqtt_client.on('message',onMessageReceived);
............
}
}
class MQTTClass2 extends MQTTBaseClass{
constructor(option) {
super(option);
var self = this;
var interval = setInterval(
function() {
self.mqttClient.publish('dddd' , 'ddd' , { retain: false },function(err){
})
}, 5000);
}
..............
}
I've made the assumption that the base class init function is being called that defines this.mqtt_client.
The issue appears to be a misspelling, you are using self.mqttClient where you should be using self.mqtt_client.
As a side note you should attempt to use a common variable naming scheme to avoid issues like this in the future: most Javascript code is written using camel case, but there is no rule against using underscores. The important thing is to be consistent.
The error is completely correct; mqttClient is undefined.
The unrelated mqtt_client field from the base class doesn't change anything.

Trying to get namespace behavior in TypeScript to work in RequireJS

I'm trying to use TypeScript to create a common library for a set of related web sites. I started off code like this:
module Lib {
export module Tools {
export class Opener {
public Path: string;
public static Open(): boolean { /* ... */ }
}
export class Closer { /* ... */ }
}
export module Controls {
export class InfoDisplay { /* ... */ }
export class Logon { /* ... */ }
}
export module Entities {
export class BigThing { /* ... */ }
export class LittleThing { /* ... */ }
}
}
var Initial: boolean = Lib.Tools.Opener.Open();
var CustomOpener: Lib.Tools.Opener = new Lib.Tools.Opener();
This worked quite well and allowed me to use some of TypeScript's nice features, like static methods and namespaced class names. As the project has grown, however, the need to use a module system for dependency resolution has become clear. My problem is that I'm a RequireJS noob so I can't quite figure out how get preserve the desirable features mentioned above to work in my project once RequireJS is in the mix. Here's my best attempt so far (which, to save space, only shows the code trail for Opener):
// ---- Opener.ts --------------------------------------------------------
/// <reference path="../typings/requirejs/require.d.ts"/>
class Opener {
public Path: string;
public static Open(): boolean { /* ... */ }
}
export = Opener;
// ---- Tools.ts --------------------------------------------------------
/// <reference path="../typings/requirejs/require.d.ts"/>
import Opener = require("./Opener");
import Closer = require("./Closer");
class Tools {
public Opener: Opener = new Opener();
public Closer: Closer = new Closer();
}
export = Tools;
// ---- ReqLib.ts --------------------------------------------------------
/// <reference path="../typings/requirejs/require.d.ts"/>
import Tools = require("./Tools");
class ReqLib {
public Tools: Tools = new Tools();
}
export = ReqLib;
// ---- App.ts --------------------------------------------------------
import ReqLib = require("./ReqLib");
var RL: ReqLib = new ReqLib();
var Initial: boolean = RL.Tools.Opener.Open(); // <== red squiggles
var CustomerOpener: ReqLib.Tools.Opener = new ReqLib.Tools.Opener(); // <== red squiggles
Visual Studio doesn't like the last two lines. It can't see the static method in the first line and it just flat out doesn't like the second because it looks like instances are being used as types. It's also the more troubling case because TypeScript kind of needs to have types to work with.
In your code RL.Tools.Opener is resolving to new Opener(); The static public static Open() does not exist on an instance but instead exists on the class Opener, hence the compiler error.
Suggestion : don't make it static. There might be other suggestions but now you know the reason for the error.
UPDATE
for new ReqLib.Tools.Opener(); you need to do new ReqLib().Tools.Opener;

Resources