ForwardRef function is used to resolve circular dependencies when working with dependency injection. Circular dependencies occur when two or more services or components depend on each other. The ForwardRef function allows you to reference a service or component that is not yet defined.
Here's how you can use ForwardRef in Angular:
- Import the ForwardRef function from the @angular/core module:
import { ForwardRef } from '@angular/core';
- Define a class or a function that represents the service or component with the circular dependency.
import { Injectable } from '@angular/core';
@Injectable()
export class ServiceA {
constructor(private serviceB: ServiceB) {}
}
@Injectable()
export class ServiceB {
constructor(private serviceA: ServiceA) {}
}
- To resolve the circular dependency, use the ForwardRef function.
import { Injectable, forwardRef } from '@angular/core';
@Injectable()
export class ServiceA {
constructor(@Inject(forwardRef(() => ServiceB)) private serviceB: ServiceB) {}
}
@Injectable()
export class ServiceB {
constructor(@Inject(forwardRef(() => ServiceA)) private serviceA: ServiceA) {}
}
By using forwardRef(() => ServiceB), we're telling Angular to wait until ServiceB is defined before injecting it into ServiceA, and vice versa.
The ForwardRef function is particularly useful when working with circular dependencies between services or components in Angular. It helps Angular's dependency injection system resolve the dependencies correctly.
Example:
// service file
import { Injectable, Inject, forwardRef } from '@angular/core';
@Injectable()
export class ServiceA {
constructor(@Inject(forwardRef(() => ServiceB)) private serviceB: ServiceB) {
this.serviceB.setValue('Hello from ServiceA');
}
getValueFromServiceB(): string {
return this.serviceB.getValue();
}
}
@Injectable()
export class ServiceB {
private value: string;
constructor(@Inject(forwardRef(() => ServiceA)) private serviceA: ServiceA) {
this.serviceA.setValue('Hello from ServiceB');
}
setValue(value: string): void {
this.value = value;
}
getValue(): string {
return this.value;
}
}
// example component
import { Component } from '@angular/core';
import { ServiceA } from './service-a.service';
@Component({
selector: 'app-example',
template: `
<p>Value from ServiceA: {{ valueFromServiceA }}</p>
<p>Value from ServiceB: {{ valueFromServiceB }}</p>
`,
})
export class ExampleComponent {
valueFromServiceA: string;
valueFromServiceB: string;
constructor(private serviceA: ServiceA) {
this.valueFromServiceA = this.serviceA.getValueFromServiceB();
this.valueFromServiceB = this.serviceA.getValue();
}
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ExampleComponent } from './example.component';
import { ServiceA, ServiceB } from './service-a.service';
@NgModule({
imports: [BrowserModule],
declarations: [ExampleComponent],
providers: [ServiceA, ServiceB],
bootstrap: [ExampleComponent],
})
export class AppModule {}
// main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);