Angular 2 - The creation of cyclic dependencies is not allowed

Utilizing a custom XHRBackend class to globally capture 401 errors, I have encountered a dependency chain issue in my code. The hierarchy is as follows: Http -> customXHRBackend -> AuthService -> Http. How can this problem be resolved?

export class CustomXHRBackend extends XHRBackend {
  constructor(browserXHR: BrowserXhr,
              baseResponseOptions: ResponseOptions,
              xsrfStrategy: XSRFStrategy,
              private router: Router,
              private authService: AuthService) {
    super(browserXHR, baseResponseOptions, xsrfStrategy);
  }

  createConnection(request: Request): XHRConnection {
    let connection: XHRConnection = super.createConnection(request);
    connection.response = connection.response
      .catch(this.handleError.bind(this));

    return connection;
  }

  handleError(error: Response | any) {
    console.log('ERROR',error['status']);
    if(error['status'] === 401) {
      this.authService.logout();
      this.router.navigate(['/']);
    }

    return Observable.throw(error);
  }
}

AuthService.ts

@Injectable()
export class AuthService {
  private loggedIn: boolean = false;

  constructor(private http: Http) {
    this.loggedIn = !!localStorage.getItem('authToken');
  }

  login(email: string, password: string): Observable<Response> {
    let headers: Headers = new Headers();
    headers.set('Content-Type', 'application/json');

    return this.http.post('https://httpbin.org/post',
      {
        email: email,
        password: password
      },
      {
        headers: headers
      })
      .map((response) => {
        let res = response.json();

        // if (res['success']) {
        if (res) {
          localStorage.setItem('authToken', res['token']);
          localStorage.setItem('refreshToken', res['refreshToken']);
          console.log('logged');
          this.loggedIn = true;
        }

        return response;
      }
    );
  }

  logout(): void {
    localStorage.removeItem('authToken');
    this.loggedIn = false;

    console.log('Logged out');
  }

  isLogged(): boolean {
    return this.loggedIn;
  }

  refreshToken(): Observable<Response> {
    let headers: Headers = new Headers();
    headers.set('token', localStorage.getItem('token'));
    headers.set('refreshToken', localStorage.getItem('refreshToken'));

    return this.http.get('https://httpbin.org/get', {
      headers: headers
    });
  }

}

Include CustomXHRBackend in app.module.ts

{
      provide: XHRBackend,
      useFactory: (browserXHR: BrowserXhr,
                   baseResponseOptions: ResponseOptions,
                   xsrfStrategy: XSRFStrategy,
                   router: Router,
                   authService: AuthService) => {
        return new CustomXHRBackend(browserXHR, baseResponseOptions, xsrfStrategy, router, authService);
      },
      deps: [BrowserXhr, ResponseOptions, XSRFStrategy, Router, AuthService]
    }

Answer №1

Have you considered exploring HTTP Interceptors? There is a helpful blog post that discusses this topic here.
For more information, a simple Google search will reveal additional resources. You can also learn how to integrate an interceptor into your App Module by visiting this link. By using interceptors, you have the ability to clone requests and include custom headers like X-CustomAuthHeader.

Answer №2

When setting up your constructor, be sure to carefully consider how you inject dependencies. It's important to avoid injecting the same dependency into multiple services. For example, CustomXHRBackend should not inject AuthService if AuthService is already injecting CustomXHRBackend.

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

Persist user input even after reloading the page

In order to enhance the user experience, I would like to implement a feature where the data entered by the user is preserved even if they refresh, reload, or close the page. This includes retaining the selections made in the select elements. Additionally, ...

Monitor changes in input display within ngIf statements

Within my code, I am utilizing an input element within a conditional statement of *ngIf: <div *ngIf='display'> <input number="number" /> </div> My goal is to be able to detect the visibility state of the input element insi ...

Only include unique objects in the array based on a common property

I am currently working with the following array: [ {name: "Mike", code: "ABC123"}, {name: "Sarah", code: "DEF456"}, {name: "John", code: "GHI789"}, {name: "Jane", code: "JKL01 ...

Discover the step-by-step guide to setting up forwarding in React Router 5

Just diving into the world of React and TypeScript. I'm working with a component called Err. Is there a way to redirect it using React Router 5? import React, { FC, Fragment, useEffect } from "react"; const Err: FC<{ error: string }> = ({ erro ...

I continue to encounter the error "Unexpected token b in JSON at position 0" when attempting to parse JSON data

Having some trouble with my code that generates an HTML page. The signup function allows users to register and create a password, while the checkpassword function is supposed to verify if the correct password is entered for the given username. I seem to be ...

Is it possible to set all UI forms to a readonly/disable mode?

We have a specific requirement where, if the user's access level is set to "READ ONLY", all form input elements should be made readonly. Our coding approach involves using a template HTML that contains widgets which are referenced in the correspondin ...

Leveraging Promise in conjunction with async/await

As I venture into the world of async/await in TypeScript, I find myself pondering a few questions. Specifically, I have been working on a function to extract an ArrayBuffer from a Blob. async function readAsArrayBuffer(blob: Blob): Promise<ArrayBuffer& ...

React: Trying to use the map function on an empty array will result in an error

I am currently facing an issue while trying to populate a shopping cart with items. Even though I have initialized the cart as an empty array, I keep encountering the following error: TypeError: cart.map is not a function ProductContext.js:34 addItemToCar ...

The attempt to test the AngularJS application using the Jasmine plugin was unsuccessful

I'm currently in the process of learning how to write test cases for my angularJS application. As a beginner, I'm searching for some sample examples of working demos. I came across an example online that uses the Jasmine plugin to test an angular ...

Personalizing specific dates in mat calendar (Angular material)

I am facing an issue with marking the days that have tasks in the mat calendar. I have been trying to troubleshoot why this code is not working as expected. Below is the typescript code snippet: dateClass(): any { return (date: Date): MatCalendarCell ...

Error: 'error' is undefined

Error Alert: The code is encountering a ReferenceError, indicating that 'error' is not defined in the following snippet: app.post('/register', function(req, res) { var hash = bcrypt.hashSync(req.body.password, bcrypt.genSaltSync(10)) ...

Transferring a JSON array from Google App Engine to Cloud Storage using GO

I am attempting to upload a JSON array to Google Cloud Storage, which is posted by an App Engine application using the code below: saveData : function saveData() { var _this = this, save = this.shadowRoot.querySelector('#save-data'), ...

Utilize Next JS pages api to generate dynamic routes based on unique ids

In the content of my website, there is a collection of objects named stories that are displayed as an array. Additionally, I have a section where each individual story is showcased in detail. I intend to enable users to click on any story link within the ...

Converting JS carousel to TS for showcasing multiple items

I am currently working on integrating a bootstrap carousel into my Angular project and I need to convert my JavaScript file to a TypeScript file. As someone who is new to this, I'm unsure of the process for converting and implementing it in a .ts file ...

Troubleshooting Vue.js Error: Uncaught ReferenceError - jQuery Undefined

I'm a beginner with Vue.js and I'm attempting to develop a custom component that utilizes the jQuery formBuilder plugin from formBuilder. However, when I try to include this component file within another component, an error occurs: Uncaught Re ...

Steps to sending an email to an administrator using PHP and jQuery

I am looking for a way to send a notification email to my site admin whenever a user submits a request via a form. Currently, I have the following code that is supposed to link to a PHP file on my server to handle the email sending: $("#modelform").submit ...

JavaScript Conversion of Characters to ASCII Values

After converting a string input into a split array, I now need to convert that split array into ASCII for evaluation. Can someone provide guidance on how to do this? ...

Establish a reactive form upon data completion (asynchronously) in Angular version 5

I've been encountering an issue with updating form values post fetching data from an API. I attempted to utilize the *ngIf technique, but unfortunately, the form remains invisible even though it is properly set. Although I cannot provide the entire p ...

Tips for navigating through an array incrementally in a Controller using input provided by the user in the View

Greetings, I am currently working on a small website project using WAMPserver. The site is structured following an MVC design pattern. In one part of the process, I generate an array of strings in the controller. My goal is to display each element of this ...