What is the purpose of a `getInstance()` method? - javascript

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.

Related

How to solve this circular dependency issue?

I have three classes : User, Account, and Model. User and Account are extending Model class.
User.js :
import Model from '#/classes/Model'
export default class User extends Model {
constructor(data) {
super(data)
}
}
Account.js :
import Model from '#/classes/Model'
export default class Account extends Model {
constructor(data) {
super(data)
}
}
And Model.js :
import Account from '#/classes/Account'
import User from '#/classes/User'
export default class Model {
static _classesMapping = {
Account,
User
}
constructor(data) {
...
}
static create(models) {
return new Model._classesMapping[this.name](models)
}
}
I want to create Account and User instances from the static method create in Model like this : Account.create()
However, i get this error when compiling: "Super expression must either be null or a function" because of the circulary dependecy issue.
I don't know how i can solve this issue without having to passing the class as an argument to the Model.create method like this, which i find ugly
Account.create(data, Account)
I want to create Account and User instances from the static method create in Model like this: Account.create()
Well, you don't need any _classesMapping for that. You can simply access the constructor by this, you don't need to go look it up by its name.
// Model.js:
export default class Model {
constructor(data) {
…
}
static create(models) {
return new this(models)
}
}
That solves your circular dependency problem by simply removing the dependency :-)
I think the best way to solve this is to move your classesMapping to an external file.
So you get
Model.js
User.js
Account.js
ClassMapping.js
Which imports User and Account and is imported by Model.js

How to design a global class for storing settings in Angular?

I have added a class like this.
export class Settings{
public data: string = "blopp";
}
When I try to access the data, it seems that the field I'm trying to assign that value to sees the class Settings itself but it doesn't recognize the data thingy.
How do I redesign the class to provide settings for other components?
I've read about #Output decorator but since I won't be binding to the values, it seems not the correct approach. I've made sure that the class is imported and recognized withing the component that's supposed to consume it. I've also tried the corresponding exposure but using a function in the class with settings - the same, failed result.
If you're using angular-cli and going to store in this class environment specific settings - you already have built in support for this.
Put the setting into environment.ts. For example:
export const environment = {
production: false,
someSetting: 'foo',
};
Then it can be consumed from anywhere within the app:
import { environment } from "../environments/environment"; //fix according to your project structure
#Injectable()
export class SampleService {
private foo = environment.someSetting;
}
Here you can find more info on how to add more environments and build you project with specific environment settings.
Your best bet for storing global settings is to use a service. The code for that looks like this:
import { Injectable } from '#angular/core';
#Injectable()
export class DataService {
serviceData: string;
}
I have a blog post about this here: https://blogs.msmvps.com/deborahk/build-a-simple-angular-service-to-share-data/
And a plunker here: https://plnkr.co/edit/KT4JLmpcwGBM2xdZQeI9?p=preview
Also, the #Output decorator is only for communication between a child component and a parent component where the child is nested within the parent.

ES6: Emitting events from static methods

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');
});
}
}

Typescript Child Namespaces and Ambient Modules

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

Dependency injection in Angular 2 when a constructor has arguments

I have a typescript class representing a model and I would like instances to communicate with an API via angular's Http service.
But the constructor of the model needs arguments when creating instances. For example something super simple:
class SomeModel{
constructor(public id:number, public name:string, ){
}
I would like to inject the Http service so it is available to my instances, but it seems like the canonical way to do this commandeers the constructor with:
constructor(http:Http)
I've been digging through the Injector docs, but it's a little sparse and I haven't found anything that works. Is there a way to get a reference to a service like Http from the DI system without using the constructor pattern?
I managed to solve the same problem using angular 4. First you create new injector that uses component injector. It knows about your SomeModel class and passes modelParams as instance of SomeModelParameters class. Then you use this newly created injector to create class instance.
#Injectable()
class SomeModel {
constructor(http: Http, someModelParamters: SomeModelParameters) { }
}
export class MyComponent {
constructor(injector: Injector) {
const modelParams = new SomeModelParameters();
const injectorWithModelParams = ReflectiveInjector.resolveAndCreate(
[
SomeModel,
{ provide: SomeModelParameters, useValue: modelParams }
],
injector);
this.someModel = injectorWithModelParams.resolveAndInstantiate([SomeModel]);
}
}
update
HTTP_PROVIDERS is long gone.
HttpClientModule is the current replacement.
original
If you inject a class that has constructor parameters the #Injectable annotation needs to be added.
#Injectable()
class SomeModel{
// constructor(public id:number, public name:string, ){
// }
constructor(http:Http) {}
}
For this to work HTTP_PROVIDERS needs to be added to bootstrap(AppComponent, [HTTP_PROVIDERS]);
See also Angular2 beta - bootstrapping HTTP_PROVIDERS - "Unexpected Token <"
If you need to pass other arguments from your component, youcoud pass them using a function instead.
Another way is to create the instance manually and request Http from the injector.
export class MyComponent {
constructor(injector: Injector) {
this.someModel = new SomeModel(Injector.resolveAndCreate(Http), 1, 2);
}
}

Categories