Get exported singleton instance from string in javascript - javascript

I have an ExampleView class which should be singleton. Inside this class I have method render which I would like to call from another js file via object name 'ExampleView'.
Here is the code:
import View from './view';
class ExampleView extends View {
render() {
return `<span>Test</span>`;
}
}
export default new ExampleView(); //<- exporting as singleton and this object I try to get via it's name
First I should do is retrieve somehow exported singleton object ExampleView from name 'ExampleView' and then call method render.
class Test {
getInstanceOfModuleByName(name) {
//window[name].render();
}
}
The problem is that I cannot find any way to get ExampleView instance from name, but my ExampleView class needs to be a singleton.
I know I can do this in following way and then call it by window['ExampleView'].render():
ExampleView = {
render: function() {
return `<span>Test</span>`;
}
}
But I really need to implement it with modulable ES6.
Can you explain me what I should do?

Populating global scope is not the ES6 way. I think you can do it like this to your export
//
// Class definition
//
window.ExampleView = new ExampleView();
export default window.ExampleView;

You just import the instance
import whateverYouWantToCallYourViewInstance from './ExampleView'
// snip
return whateverYouWantToCallYourViewInstance.render();
It will be the same object.
Worth noting: Singletons are evil. Using the ES module system to pass instances around is a bit of abuse.

Related

How to use disconnect() to close a Uppy JS instance – Stimulus

When I click the "back button", my Uppy form is briefly loaded twice. How can I get Stimulus to close the previous Uppy instance when I leave the page?
Following the Uppy Docs, I'm hoping something like this (code below) but I get the error: uppy is nil or undefined on disconnect().
How can I bind uppy.close() to the original instance of Uppy?
import { Controller } from "#hotwired/stimulus"
import Uppy from "#uppy/core"
export default class extends Controller {
connect() {
const uppy = new Uppy()
}
disconnect() {
// This causes an error
uppy.close();
}
}
The problem is that you are trying to access uppy as a local variable that you have set in the connect method. However, methods to get get access to other methods' scope, which is why uppy is undefined when you try to access it in the disconnect method.
Instead, you have a few options.
Option 1 - Store the variable on the class instance
Each class instance has its own this variable, and you an easily store values on it as it is an object.
By convention, the below example uses this._uppy (with an underscore) but any name will work.
import { Controller } from "#hotwired/stimulus";
import Uppy from "#uppy/core";
export default class extends Controller {
connect() {
// 'store' the uppy instance against your class instance
this._uppy = new Uppy();
}
disconnect() {
// read the instance and access its close method
this._uppy.close();
}
}
Option 2 - Store the variable globally
Another way to think about this is that you do not want to create a new Uppy instance if there is already one created.
You can store this instance on window, although this breaks the concept of your file being an isolated module.
Another way is to store the instance in the module file itself, this may create some edge case issues for unit tests but see how you go.
import { Controller } from "#hotwired/stimulus";
import Uppy from "#uppy/core";
// declare a variable in the 'module' scope (this file).
let uppy;
export default class extends Controller {
connect() {
// if uppy has already been instantiated - do not create a new one
if (uppy) return;
// 'store' the uppy instance against your module scoped global variable
uppy = new Uppy();
}
disconnect() {
// read the instance and access its close method
uppy && uppy.close();
// reset the variable to null
uppy = null;
}
}

Should/do I have to export returning class returned by another exported class in Javascript ES6?

Consider the following module:
export class Bar {
generateFoo() {
return new Foo(1);
}
}
class Foo {
constructor(fooValue) {
this.fooValue = fooValue;
}
doFoo() { console.log(this.fooValue); }
}
Should I export Foo too in any situation? Why/Why not?
Should I export Foo too in any situation? Why/Why not?
The only reason to export something from a module is if you want code from outside to be able to call it or reference it directly. If the only way you want your clients to be able to create Foo objects is by calling bar.generateFoo(), then there is no reason to export Foo. In Javascript, you can fully reference all Foo methods on an already constructed object without exporting the class itself.
If, on the other hand, you want some client of your module to be able to directly instantiate a Foo object with new Foo(someValue), then you would need to export Foo to make that possible.
Exporting a class is exporting the constructor function. So, you need to do that export if you want someone to be able to call the constructor directly (e.g. construct a new object with new Foo()). If they don't need to call the constructor directly, then you don't need to export it.

Angular like dependency injection of services in Javascript

I am writing a Javascript npm package. In my code I have a single class which I want to act like an angular service. Only one instance of that class should be created and needs to be shared wherever wanted in the project.
//this class object would be shared across project and only one object can be created. also, its implementation could change in future
export class SharedClass {
constructor(somethingImp) {
}
//more methods
}
export class ProjectClass1ThatNeedsSharedClassObj {
//it should get the required object
}
export class ProjectClass2ThatNeedsSharedClassObj {
//it should get the required object
}
How can I write a simple DI to achieve this functionality?
If you want enforce a single object through all methods of DI, you can use a static variable. This is the pattern I normally use
export class SearchProvider {
private static _default: SearchProvider
constructor() {
}
static get Default() {
return this._default || (this._default = new SearchProvider())
}
}
export class Consumer() {
private SearchProvider _provider = SearchProvider.Default;
}
1)Create that class as a service with #Injectable decorator
2)Import that class into class where you want to use it
3)create a instance of service class into that class
4)now you can access methods of service class using instance created in constructor
using this keyword & . operator
5)You have to write service class once & use it many times as you want
Happy coding

How can I export classes from Typescript factory functions?

I'm working on an Angular/Typescript application that has been partially converted from Javascript (there are class definitions, but fields and variables are mostly untyped, and the style remains very js-like).
Many classes are defined inside factory functions like this:
export default function SomeClassFactory($http) {
class SomeClass {
constructor() {
// initialise
}
someMethod($http) {
// do something with $http
}
}
return SomeClass;
}
It seems to be impossible to export inner classes defined in this way for use in import statements. I have tried moving the class declaration outside the factory function, but this fails when the class uses values that Angular injects, as in the example. (Presumably these injected values are effectively static members of the class.)
How can I export a class defined in this way?

How to make Typescript Dojo Widget Newable?

From within an existing Dojo widget, I want to create an instance of some other widget, which has been transpiled from TypeScript. Sounds simple -- but for some reason the transpiled widget is not "newable", unless I specify the classname twice. I can't update all of that existing code, so I need the transpiled widget to be "newable".
Here is the very simple MyTypeScriptWidget.ts:
import _WidgetBase = require("dijit/_WidgetBase");
export class MyTypeScriptWidget extends dijit._WidgetBase
{
constructor(params?: Object, srcNodeRef?: HTMLElement)
{
super(params, srcNodeRef);
}
}
Then, over in the existing Dojo JavaScript (not TypeScript) widget, I want to new up an instance of MyTypeScriptWidget. So, here's what I have to do in MyJavaScriptWidget.js
var myInstance = new MyTypeScriptWidget.MyTypeScriptWidget();
Notice how I have to type it twice? Why? What am I doing wrong? How can I change MyTypeScriptWidget.ts so that MyJavaScriptWidget.ts can use AMD to create an instance like I did before, like this:
define(['dijit/_WidgetBase', 'tool/MyTypeScriptWidget'], function(_WidgetBase, MyTypeScriptWidget) {
return declare([_WidgetBase], {
var myInstance = new MyTypeScriptWidget();
});
});
In TypeScript, export normally defines members on the module's export object. If you want to define a single thing to be exported, you need to use export =.
class MyTypeScriptWidget ... {
...
}
export = MyTypeScriptWidget;

Categories

Resources