I found some weird behavior that if I declare variable with a type of the class and without initialization. I can't access methods of this class, this for sure right.
BUT if I declare variable in constructor also without initialization, then I can use methods of this class.
This behavior only at Angular, I tried the same thing at TS, it didn't 'work.
I only can explain it for myself, that Angular autmaticle initializes values inside constructor, am I right? Check code
In my code I just trying to get wrong url, and then to handle error
This is an error :
ERROR TypeError: Cannot read properties of undefined (reading 'handle')
at ProductsService.errorHandler
Code:
export class ProductsService {
//this initialization will work
constructor(private http: HttpClient, private errorService: ErrorService) {
}
getProducts(): Observable<Iproduct[]>{
return this.http.get<Iproduct[]>('https://fakestoreapi.com/productsp',{
params: new HttpParams().append('limit', '8')
})
.pipe(
tap((value) => console.log(value)),
delay(2000),
catchError(this.errorHandler.bind(this))
);
}
// no problem to call the method
private errorHandler(error: HttpErrorResponse){
this.errorService.handle(error.message);
return throwError(() =>error.message);
}
}
// this leads to error
export class ProductsService{
//different decloration of the variable errorService
private errorService: ErrorService
//like this will work when manually initialize
//private errorService: ErrorService = new ErrorService()
constructor(private http: HttpClient,){
}
getProducts(): Observable<Iproduct[]>{
return this.http.get<Iproduct[]>('https://fakestoreapi.com/productsp',{
params: new HttpParams().append('limit', '8')
})
.pipe(
tap((value) => console.log(value)),
delay(2000),
catchError(this.errorHandler.bind(this))
);
}
private errorHandler(error: HttpErrorResponse){
//method not defined
this.errorService.handle(error.message);
return throwError(() =>error.message);
}
}
You are experiencing the dependency injection pattern which Angular embrasses.
Dependency injection, or DI, is one of the fundamental concepts in Angular. DI is wired into the Angular framework and allows classes with Angular decorators, such as Components, Directives, Pipes, and Injectables, to configure dependencies that they need.
Two main roles exist in the DI system: dependency consumer and dependency provider.
Angular facilitates the interaction between dependency consumers and dependency providers using an abstraction called Injector. When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry. Angular creates an application-wide injector (also known as "root" injector) during the application bootstrap process, as well as any other injectors as needed. In most cases you don't need to manually create injectors, but you should know that there is a layer that connects providers and consumers.