Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get new instances of a class using Injector instead of singleton

I have two injectable classes in my angular application

@Injectable()
class B {}

@Injectable()
class A {
  constructor(b:B) { }
}

I want class A to be Singleton and class B to be Transient

I came to know I can use ReflectiveInjector.resolveAndCreate in class A to get an instance of class B. Any better way of achieving this ?

like image 911
Ravi Avatar asked Oct 19 '25 03:10

Ravi


2 Answers

Since all existing recipes for providers create singletons, even factory, you can create your own injector, inherit all providers from component injector and use resolveAndInstantiate method to get new instances every time:

import { Component, Inject, Injector, ReflectiveInjector } from '@angular/core';

class P {
}

const ps = [];

class C {
  constructor(@Inject(P) p) {
    ps.push(p);
  }
}

@Component({
  moduleId: module.id,
  selector: 'my-app',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css']
})
export class AppComponent {
  name = 'Angular';

  constructor(injector: Injector) {
    const parent = ReflectiveInjector.resolveAndCreate([P], injector);
    const child = parent.resolveAndCreateChild([C]);
    const c1 = child.resolveAndInstantiate(C);
    const c2 = child.resolveAndInstantiate(C);
    console.log(c1 === c2); // false

    console.log(ps[0] === ps[1]); // true

  }
}

Here is the demo.

Also bear in mind that ReflectiveInjector is deprecated in @5.x.x. And it seems that there's no alternative in the new StaticInjector. I reported an issue about that.

like image 100
Max Koretskyi Avatar answered Oct 21 '25 16:10

Max Koretskyi


There is a way to solve this using StaticInjector and functional Javascript. Using Max Koretskyi answer, with few modifications I come up with this:

import { Component, Inject, Injector } from '@angular/core';

class P {
}

const ps = [];

function pFactory() {
  return () => new P();
}

@Component({
  moduleId: module.id,
  providers: [{provide: pFactory, deps: [], useFactory: (pFactory)}],
  selector: 'my-app',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css']
})
export class AppComponent {
  name = 'Angular';

  constructor(@Inject(pFactory) pf) {
    let fn = pf.get(pFactory)
    ps.push(fn());
    ps.push(fn());
    console.log(ps[0] === ps[1]); // false
  }
}
like image 45
Chuma Avatar answered Oct 21 '25 18:10

Chuma