What is the best way, or is there a best practice or workaround, to emit an event from a static method call?
Let's say I have a ES6 class that calls upload and uploads files in a directory recursively to some endpoint and I want an event emitted after each individual file is successfully uploaded. I know I can have the class inherit EventEmitter, but the .on and .emit functions don't exist without instantiating a new instance of the class. Is there any way around this?
There is no way around it. If you want to call .emit(), then you need an instance of EventEmitter somewhere that you can call the .emit() on. And, of course, this makes sense because your other code has to have something to call .on() with to register listeners on.
If you don't need a separate emitter for every object, you can make just one shared emitter that you either store in some other object, in some useful scope or in module scope or you can even make the single emitter be a class static. If the emitter instance is a class static (initialized at startup), then the static methods could all reference it.
jfriend00 is right, there is no way around without creating an instance of EventEmitter, but using the Singleton pattern it is possible to implement a solution to your problem, for example:
This is the singleton "eventEmitterHandler.ts"
import {EventEmitter} from "events";
export default class EventEmitterHandler extends EventEmitter {
private static instance: EventEmitterHandler;
private constructor() {
super();
}
static getInstance() {
if (!EventEmitterHandler.instance) {
EventEmitterHandler.instance = new EventEmitterHandler();
}
return EventEmitterHandler.instance;
}
}
The class with the static method
import EventEmitterHandler from "./eventEmitterHandler";
export default class ClassA {
constructor() {}
public static staticMethod() {
EventEmitterHandler.getInstance().emit('wave');
}
}
The class with the subscription to the event
import EventEmitterHandler from "./eventEmitterHandler";
export default class ClassB {
constructor() {
EventEmitterHandler.getInstance().on('wave', () => {
console.log('constructor wave');
});
}
}
Related
I am looking at a user service, my understanding is it's similar to a user service in Nest, but not really.
In it I see the following:
export class UsersService {
private usersDao: UsersDao
constructor() {
this.usersDao = UsersDao.getInstance();
}
}
static getInstance(): UsersService {
if (!UsersService.instance) {
UsersService.instance = new UsersService();
}
return UsersService.instance;
}
What is that getInstance() doing exactly? And why not just:
export class UsersService {
constructor(private usersDao: UsersDao) {}
}
What is the goal of getInstance()?
Usually this is part of the singleton pattern. Basically one class that, once instantiated, any subsequent classes will refer to that instance, rather than creating a fresh instance each time.
https://en.wikipedia.org/wiki/Singleton_pattern
Its useful for a class where something complex needs to happen when it is first constructed, but all following calls just need access to the properties.
I'd also like to mention that you can (in JavaScript specifically) export an instance, and all modules that import the module will have access to the same instance.
I have a class in my react app which uses 'Builder Pattern' and I've imported it in some nested components in my page. for example in parent component and child component, too.
But it seems it calls the class's constructor once! and in second instantiate it has existing data which I've added in previews in previews instantiate. (Not a new and clean instantiate!)
// [Builder pattern]
class Requester {
constructor() {
this.definedHeaders = {}
console.log('construct', this)
}
contentType(contenttype) {
this.definedHeaders['Content-Type'] = contenttype
return this;
}
async get(url) {
// ...
}
async post(url, data = {}, isFormData = false) {
// ...
}
}
export default new Requester();
ES modules are evaluated only once, when they are imported the first time. This trait is common to all JavaScript module implementations.
Because of that, exporting class instance is a common way to make class a singleton. That a class itself isn't exported prevents from creating additional instances.
If the intention is to not have a single instance, a class itself should be exported:
export default class Requester {...}
And instantiated in places where it's used:
import Requester from '...';
const requester = new Requester;
I am building a typescript mixin for web components to add drag behvior. Until now everything worked pretty nice. However I have a difficult problem when trying to remove an event listener after the draggable web component was disconnected.
drag.ts - Adds drag behavior to HTMLElements
type Constructor = new (...args: any[]) => HTMLElement
export function Drag<BC extends Constructor>(BaseClass: BC) {
return class Drag extends BaseClass {
constructor(...args: any[]) {
super(...args)
// Somehow I need to remove this listener when the component is disconnected
document.addEventListener(UPDATE_ACTIVE_DRAG_SET, this.handleToggleDrag)
}
disconnectedCallback() {
// This mehods must be implemented by a web component
// Not all web components that will receive the drag behavior
// will ahve a disconnectedCallback defined
// So typescript must be right when it gives an error
super.disconnectedCallback()
// These work just fine (HTMLElement implements them)
super.innerHTML
super.querySelector('div')
}
// ...more stuff here
}
}
main-menu.ts - Possible candidate for drag behavior
export class MainMenu extends HTMLElement{
// ... implementation of the web component
// <!> It is very likely that not all components will implement this
disconnectedCallback() {}
}
window.customElements.define('main-menu', DragAndDropLayout(MainMenu))
The only idea I have so far is monkey patching the HTMLElement to include a dummy disconnectedCallback so that super.disconnectedCallback will not complain with this error: Property 'disconnectedCallback' does not exist on type 'HTMLElement'. I haven't tried it yet. Is there a nicer way to fix this?
Your mixin can test for the presence of a method in a superclass:
disconnectedCallback() {
if (super.disconnectedCallback) {
super.disconnectedCallback();
}
// Do mixin work here.
}
This Elix project, which makes heavy use of mixins, explores this topic in its composition rules for mixin methods and properties.
We use this approach successfully with TypeScript. Note that it's also possible to create TypeScript definition files for your mixin such that TypeScript will know what mixin methods/properties are available to a component using your mixin. Our current definition for a Mixin generic type is at https://github.com/elix/elix/blob/master/src/shared.d.ts.
I'm encapsulating a Menu called JellMenu, and I want to expose CustomMenuItem like JellMenu.Item instead of import CustomMenuItem. I have no idea how to do.
I took look at react-native-viewpager source code, and I think this maybe helpful:
var ViewPager = React.createClass({
statics: {
DataSource: ViewPagerDataSource,
},
It will expose ViewPagerDataSource as ViewPager.DataSource, right? I don't know exactly. what's the meaning of the keyword statics in Es5, and what's the alternative in Es6? Thank you in advance.
It isn't a keyword, it's just a property name in an object initializer being passed to React.createClass. From the documentation, it's used to specify static (non instance-specific) parts of a React class:
The statics object allows you to define static methods that can be called on the component class.
Although statics only works for React.createClass, you can still write static methods in ES6 notation. If you are using ES7, then you can also write static properties.The statics object allows you to define static methods that can be called on the component class. For example:
var MyComponent = React.createClass({
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
},
render: function() {
}
});
MyComponent.customMethod('bar'); // true
Methods defined within this block are static, meaning that you can run them before any component instances are created, and the methods do not have access to the props or state of your components. If you want to check the value of props in a static method, have the caller pass in the props as an argument to the static method.
Also, You can write statics inside ES6+ classes this way:
class Component extends React.Component {
static propTypes = {
...
}
static someMethod(){
}
}
Or outside the class like this:
class Component extends React.Component {
....
}
Component.propTypes = {...}
Component.someMethod = function(){....}
I've got a conundrum for you. I'm fairly new to Typescript, but I've enjoyed the experience thus far. Wanting to be a good developer and logically group my modules into namespaces I've come across a rare? issue. Here's the simplest example to recreate the problem.
Lets say you got a class... we'll call it ClassA, which references a class aptly named ClassB which resides in a child namespace.
namespace Foo {
export class ClassA {
public classB: Bar.ClassB;
public constructor() {
}
}
}
and
namespace Foo.Bar {
export class ClassB {
public constructor() {
}
}
}
Typescript couldn't be happier with this. Well when I want to import things for ClassA, I'll put it inside the namespace like so:
namespace Foo {
import SomeClass = SomewhereElse.SomeClass;
export class ClassA {
public classB: Bar.ClassB;
public constructor() {
}
}
}
Again... we cool. But what if I wanted to import an ambient module?
namespace Foo {
import * as SockJS from "sockjs-client"; // TS1147 GRUMBLE! CAN'T DO DAT HERE!
export class ClassA {
public classB: Bar.ClassB;
public constructor() {
}
}
}
Ok, that's fine. I'll just move it outside the namespace like it's telling me to.
import * as SockJS from "sockjs-client";
namespace Foo {
export class ClassA {
public classB: Bar.ClassB; // TS2503:Now you're just a Bar that I used to know
public constructor() {
}
}
}
Suddenly Typescript gets amnesia and doesn't know what Bar is. It doesn't recognize child namespaces. I've tried several ways to make it remember like nesting the namespaces or exporting them, but nothing will make it recognize this. What's the dilly yo? Any of you cool cats know what's going on or how I can resolve it and keep my child namespaces?
Suddenly Typescript gets amnesia and doesn't know what Bar is. It doesn't recognize child namespaces. I've tried several ways to make it remember like nesting the namespaces or exporting them, but nothing will make it recognize this. What's the dilly yo
Its because namespaces are global. And modules are modular. So as soon as you import a module into your file, your file becomes a module. https://basarat.gitbooks.io/typescript/content/docs/project/modules.html
Suggestion
Please use modules. There are plenty of reasons : https://github.com/TypeStrong/atom-typescript/blob/8d43dd1b930a6df0ce62454a1560acfb7eee24c9/docs/out.md