Angular DI system unfolded thoroughly in simple terms for practical use
How do we create an instance
myInstance = {};
instanceOutOfClass = new MyClass(...dependencies);
property = 5;
member = 'value';
Instances could be simply created this way but to lazily create these instances (at the time of the request, the first time it’s requested through DI), also providing dependencies to those instances at runtime easily and to facilitate providing the same (singletons) throughout the hierarchy Angular has something called Providers which we usually call Services.
What can act as a Provider
Any Class having the Injectable decorator
@Injectable()
export class MyClass {}
// providing it,
// its instance will sit at the root unless provided again
@Injectable({provideIn: 'root'})
export class MyClass {}
// or providing it at a particular level
providers: [MyClass]
Injection Tokens
export const MY_INJECTION_TOKEN = new InjectionToken<MyType>('my.token');
// providing it
export const MY_INJECTION_TOKEN = new InjectionToken<MyType>('my.token', {
provideIn: 'root'
});
// providing the blueprint too
// factory function will be invoked to retrieve it's instance
export const MY_INJECTION_TOKEN = new InjectionToken<MyType>('my.token', {
factory: () => {
const otherInstance = inject(MyOtherInstance); // utilising the DI
// return () => otherInstance.token;
// return otherInstance.getToken(); // sync call
// return anything here you want use as an instance;
return {token: otherInstance.token, id: 5};
}
})
Providing the definition or value for a provider later
Even string tokens can be used as a provider (NOT suggested)
Better use injection token instances as it’s easier to reference and for type safety (the modern
inject
function keep the type definition intact).
// provide static value for this token
providers: [{provide: 'SOME_TOKEN', useValue: localStorage}]
// use MyClass to create & provide an instance for this token
providers: [{provide: 'SOME_TOKEN', useClass: MyClass}]
// call myFactory function to retrieve an instance for this token
const myFactory = () => {x: 5, y: 8};
providers: [{provide: 'SOME_TOKEN', useFactory: myFactory}]
// use an existing instance of MyClass whenever providing for this token
providers: [{provide: 'SOME_TOKEN', useExisting: MyClass}]
// Using that string token in the DI
const myStringToken = inject('SOME_TOKEN');
// or in the constructor
constructor(@Inject('SOME_TOKEN') myStringToken) {}
The first time angular finds a request for these classes to be injected, their instances are created and stored in its injector service for future references in other places.
/**
* These must be called from an injection context
* such as a constructor, a factory function, a field initializer,
* or a function used with `EnvironmentInjector#runInContext
*/
// instance is requested through DI
const myClassInstance = inject(MyClass);
// instance is requested through DI
constructor( private myClassInstance: MyClass) {}
Instances that angular creates from template and stores in it’s injector at that hierarchy
Any time we place a component
, directive
, or pipe
inside our template an instance is created for that class at that level.
<my-component></my-component> // instance created for MyComponent Class
<p myDirective></p> // instance created for MyDirective Class
<span>{{ 'some content' | myPipe}}</span> // instance created for MyPipe Class
<ng-container *ngIf="!!exp"></ng-container> // instance created for NgIf Class
and we can access all these instances if we are inside an injection context ( in the field initializer or constructor within your components, directives, pipes, services, etc) according to where they are placed lexically in your application hierarchy.
For example, within SideNavComponent
we can get access to the instance of MainComponent
(parent, lexically placed above in the hierarchy) like:
@Component({selector: 'ipm-side-nav'})
export class SideNavComponent {
constructor(private mainComponent: MainComponent) {}
}
In the next blog post, we’ll cover awesome applications of using the DI in Angular applications for various use cases.
Thanks for that like by the way😉, please feel free to connect for any feedback, query or just to say Hi! on my LinkedIn