Integrating one service into another allows for seamless access to the imported service's properties and methods within an Angular

After reviewing the content at https://angular.io/guide/dependency-injection-in-action, it appears that what I am trying to achieve should be feasible. However, I encounter this error when attempting to invoke a method on my injected service from another service:

TypeError: Cannot read property 'isLoggedIn' of undefined at CatchSubscriber.handleError [as selector] (project.service.ts:30) at CatchSubscriber.error (catchError.js:29) at TapSubscriber._error (tap.js:56) at TapSubscriber.error (Subscriber.js:55) at MapSubscriber._error (Subscriber.js:75) at MapSubscriber.error (Subscriber.js:55) at FilterSubscriber._error (Subscriber.js:75) at FilterSubscriber.error (Subscriber.js:55) at MergeMapSubscriber.notifyError (OuterSubscriber.js:7) at InnerSubscriber._error (InnerSubscriber.js:14)

Below is my ProjectService code snippet where I'm injecting the UserService:

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Observable, throwError, of } from 'rxjs';
import { catchError, tap, map } from 'rxjs/operators';
import { AuthHeader } from '../../Shared/Helpers/AuthHeader';
import { UserService } from '../../User/Services/user.service';

@Injectable({
  providedIn: 'root'
})
export class ProjectService {

  constructor(private http: HttpClient, private userService: UserService) {

  }
  private projectsApiEndPointRoot = '/api/ProjectApi/';
  test(): Observable<number> {
    return <Observable<number>>this.http.get<number>(this.projectsApiEndPointRoot + "getimages/8", { headers: AuthHeader.getAuthHeader() }).pipe(
      tap(data => console.log(data)),
      catchError(this.handleError)
    );
  }

  private handleError(err: HttpErrorResponse) {
    let errorMessage = '';
    if (err.error instanceof ErrorEvent) {
      errorMessage = `An error occurred: ${err.error.message}`;
    } else {
      if (err.status == 401 || err.status == 403) {
        console.log(this.userService.isLoggedIn());
      }
      else {
        errorMessage = `Server returned code: ${err.status}, error message is: ${err.message}`;
      }
    }
    console.error(errorMessage);
    return throwError(errorMessage);
  }
}

The UserService includes a method that is intended to return a boolean value indicating whether the user is logged in. While this method works successfully across multiple components, it encounters an issue when accessed from another service.

Could this action potentially not be permissible?

UPDATE: Including excerpts from the UserService for clarification:

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError, of, BehaviorSubject } from 'rxjs';
import { catchError, tap, map } from 'rxjs/operators';
import { EmailModel } from '../Models/EmailModel';
import { ILoginRequest } from '../Interfaces/ILoginRequest';
import { ILoginResponse } from '../Interfaces/ILoginResponse';
import { IRegistrationRequest } from '../Interfaces/IRegistrationRequest';
import { Router } from '@angular/router';


@Injectable({
  providedIn: 'root'
})
export class UserService {
  constructor(private http: HttpClient, private router: Router) { }
  private usersApiEndPointRoot = 'api/UserApi/';

  private loggedIn = false;
  ...

  isLoggedIn() {
    return this.loggedIn;
  }


  private handleError(err: HttpErrorResponse) {
    let errorMessage = '';
    if (err.error instanceof ErrorEvent) {
      errorMessage = `An error occurred: ${err.error.message}`;
    } else {
      errorMessage = `Server returned code: ${err.status}, error message is: ${err.message}`;
    }
    console.error(errorMessage);
    return throwError(errorMessage);
  }
}

Answer №1

It seems like the issue lies in passing the function on the user service. This causes the value of this to become the window when it is called.

To resolve this problem, try using a lambda function instead of passing the function to the catchError function. By making a simple change to the test() method as shown below, you can ensure that the context of 'this' is preserved:

test(): Observable<number> {
  return <Observable<number>>this.http.get<number>(this.projectsApiEndPointRoot + 
      "getimages/8", { headers: AuthHeader.getAuthHeader() }).pipe(
    tap(data => console.log(data)),
    catchError(err => this.handleError(err)) // <--
  );
}

Answer №2

It is important to utilize arrow functions in the catchError method in order to maintain access to the class context through "this".

catchError((err) => this.handleError(err))

Failing to do so will result in the loss of context.

Answer №3

Adding my comment as an answer too because it offers a unique perspective compared to the rest.

To modify your method signature, follow this format:

private errorHandling = (err: HttpErrorResponse) => {...}

Afterwards, you have the option to retain catchError(this.errorHandling) if desired.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

NextImage encountering issues in Internet Explorer 11

In my TypeScript setup, here is a snippet from my package.json file: "dependencies": { "@tailwindcss/typography": "^0.4.1", "@webcomponents/shadydom": "^1.7.4", "cookie": "^0.4.1", " ...

Transmitting JSON and FormData between Angular and Spring

Angular Tutorial processRegistration(user: any, file: File): Observable<any>{ let formData = new FormData(); formData.append("user", JSON.stringify({username:'User'})); formData.append("file", file); return this. ...

Dynamic Object properties are not included in type inference for Object.fromEntries()

Hey there, I've been experimenting with dynamically generating styles using material UI's makeStyles(). However, I've run into an issue where the type isn't being correctly inferred when I use Object.fromEntries. import * as React from ...

When you compile TypeScript with the target set to 'ES3' or 'ES5', it creates an internal structure

Recently delved into the world of TypeScript and experimenting with webpack ts-loader and babel-loader to compile and transpile TypeScript into ES5. However, I came across a compiler option in tsc that can target 'ES5', which made me question the ...

Verify the completeness of data types within an array in typescript

I am currently developing a comprehensive match function that I want to ensure is exhaustive during compile time. Although adding a default case would help with this, I am intrigued by some interesting dependent typing techniques I have come across. It wou ...

Using Angular 6 shortcodes in HTML

Is there a way to save an element in HTML as an alias for repeated use in Angular 6 without using *ngIf directive? For instance, consider the following code snippet: <dumb-comp [name]="(someObservable | async).name" [role]="(someObservable | a ...

Angular2 route-driven themes

Exploring Different Themes for Two Routes: /books and /paintings Seeking a Solution to Include Specific Stylesheet Links in index.html For the /books route, I wish to include: <link rel="stylesheet" href="/assets/css/reading-theme.css" /> And for ...

Do Angular lifecycle hooks get triggered for each individual component within a nested component hierarchy?

I'm exploring the ins and outs of Angular lifecycle hooks with a conceptual question. Consider the following nested component structure: <parent-component> <first-child> <first-grandchild> </first-grandchild& ...

Saving JSON data in a variable or array post subscription: What's the preferred method?

I have been receiving JSON files in the following format: {streetAddress: "Kosterlijand 20", postalCode: "3980", city: "Bunnik", country: "Netherlands"} Although the length of these files varies, the structure always remains the same: {key: "string valu ...

Consecutive HTTP requests in Angular using rxjs

Currently working on a function that utilizes concatMap to perform sequential HTTP calls, such as adding a person, using the returned information to add a contact, and then adding some accounts. This function takes in a list (in my case, portfolios) and f ...

"Alert: The ToastData is nowhere to be found in

In my previous Angular 5 application, I was using ng2-Toasty for displaying toasts. However, since ng2-Toasty does not support Angular 8, I am now trying to switch to ngx-toastr. Upon implementation, I noticed that ngx-toastr does not have an equivalent o ...

Customizing tsconfig.json: Enhancing an existing object by adding new keys in TypeScript

Is it possible to achieve the following functionality by default? let j = {a:1}; j.b = 2; I am aware that there are alternative solutions, but I am curious if this specific task can be accomplished by solely modifying tsconfig.json? ...

Error in util.js: process variable is not defined in Angular 15

As I work on integrating the Voice JavaScript SDK into my Angular 15 application, I encountered an error after installing the necessary npm packages. When running the app, a reference error is displayed in the browser console and the UI fails to load. Unca ...

Managing Prisma error handling in Express

Dealing with error handling using ExpressJS and Prisma has been a challenge for me. Anytime a Prisma Exception occurs, it causes my entire Node application to crash, requiring a restart. Despite looking at the Prisma Docs and doing some research online, I ...

Utilize Array.push to add 2 new rows to a table using Angular 4

I have two arrays that are almost identical, except for two items which are the fakeDates: this.prodotti.push({ idAgreement: this.idAgreement,landingStatus: this.landingStatus, landingType: this.landingType, startDate: this.startDate, expirationDate: thi ...

How can I simulate event data while testing a function that is triggered when an event is emitted from another component in Angular integration testing?

Within component A, there is a function responsible for updating the view based on data emitted from component B. The aim is to simply call this function and pass the data without integrating with component B as it would be too complicated for this particu ...

Having trouble locating the Angular Material core theme within the asp.net core 2.0 template using Angular 5

CustomConfig.js const treeModules = [ '@angular/animations', '@angular/common', '@angular/compiler', '@angular/core', '@angular/forms', '@angular/http', '@angular ...

Guide on retrieving image file name and extension with camera plugin in Ionic 2

Hi everyone, I'm looking for a way to retrieve the image name with its extension using the camera plugin in Ionic 2. Any tips on how to achieve this? Thank you! Below is the code I have so far: // Function for selecting an image ImagePick() { ...

Displaying Firebase values in an Angular 2 list is a breeze

Here is the functionality to load, add, and mark ToDo as Finished: todos: FirebaseListObservable<any>; ngOnInit(){ this.todos = this._af.database.list('todos') } addTodo(newTodo: string){ this.todos.push({ ...

Adjust the size of the plane in Three.js to match the entire view

English is not my strong suit, as I am Japanese. I apologize for any confusion. Currently, my focus is on studying Three.js. I aim to position a Plane directly in front of the camera as the background. My goal is to have the Plane background fill the en ...