How do I resolve this Angular 7 "Circular dependency detected" warning

10,092

There is no one direct way around it. I understand your use-case though, and kinda support it. You should not have this kind of logic in your component. It should be done in a service. You are right about that. I'm not entirely sure it's the best idea to reuse the Routes export. It feels like you are better of using the Router.config property. Which should contain the entire route config:

@Injectable({
  providedIn: 'root'
})
export class PagesService {
  readonly pages: Routes = this.router.config;
  private pagesChanged: EventEmitter<Page[]> = new EventEmitter<Page[]>();

  constructor(private location: Location, private router: Router) {
    this.setPagesFullPath();
    console.log(this.pages);
  }
}

If this, for whatever reasons doesn't work. The way to get rid of circular dependencies is by splitting into multiple files. The main issue is your routePages. You can convert this to two files. One being pages.ts:

pages.ts

export enum PageRoute {
  Login: 'login',
  SignUp: 'sign-up'
}

export interface PageData {
  title: string;
  description: string;
  keywords: string;
  icon?: string;
  hasBreadcrumb: boolean;
}

export const PageRouteData: Record<PageRoute, PageData> {
  [AppPage.Login]: {
    title: 'Login',
    description: '',
    keywords: '',
    icon: 'fingerprint',
    hasBreadcrumb: true
  },
  [AppPage.SignUp]: {
    title: 'Sign up',
    description: '',
    keywords: '',
    hasBreadcrumb: true
  }
}

And another file which actually contains your routes which are digested by the router:

app.routes.ts

export const routePages: Page[] = [
  {
      path: '',
      redirectTo: PageRoute.Login,
      pathMatch: 'full'
  },
  {
      path: PageRoute.Login,
      component: LoginComponent,
      data: PageRouteData[PageRoute.Login]
  },
  {
      path: PageRoute.SignUp,
      component: SignupComponent,
      data: PageRouteData[PageRoute.SignUp]
  }
];

Side note: pathMatch is only necessary if you have a redirectTo

This way you do not need to import the app.routes in your PagesService and the circular dependency is resolved

Share:
10,092
Admin
Author by

Admin

Updated on June 24, 2022

Comments

  • Admin
    Admin almost 2 years

    In my Angular 7 project, I want to have a file "pages.ts" where I export the routes my app is going to have. These are imported by "app-routing.ts" to be used by the RouterModule, and also imported by "pages.service.ts" where I want to manage the data of those routes. Now, in one of my components "test-one.component.ts" I want to use that service "pages.service.ts" so I can get for example the data of a route by its path or title. Everything works properly but this warning appears.

    WARNING in Circular dependency detected: src/app/pages/test-one/test-one.component.ts -> src/app/core/services/pages.service.ts -> src/app/core/constants/pages.ts -> src/app/pages/test-one/test-one.component.ts

    "pages.ts"

    import { Page } from '../../core/models/page.model';
    import { LoginComponent } from '../../pages/login/login.component';
    import { SignupComponent } from '../../pages/signup/signup.component';
    
    export const routePages: Page[] = [
        {
            path: '',
            redirectTo: 'login',
            pathMatch: 'full'
        },
        {
            path: 'login',
            component: LoginComponent,
            canActivate: [],
            data: {
                title: 'Login',
                description: '',
                keywords: '',
                icon: 'fingerprint',
                hasBreadcrumb: true
            },
            pathMatch: 'full'
        },
        {
            path: 'sign-up',
            component: SignupComponent,
            canActivate: [],
            data: {
                title: 'Sign up',
                description: '',
                keywords: '',
                hasBreadcrumb: true
            },
            pathMatch: 'full'
        }
    ];
    

    "app-routing.module.ts"

    import { routePages } from './core/constants/pages';
    import { NgModule } from '@angular/core';
    import { RouterModule } from '@angular/router';
    
    @NgModule({
      imports: [RouterModule.forRoot(routePages, { scrollPositionRestoration: 'enabled' })],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
    

    "pages.service.ts"

    import { routePages } from './../constants/pages';
    import { Page, PageData } from './../models/page.model';
    import { Router } from '@angular/router';
    import { Injectable, EventEmitter } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class PagesService {
      pages = routePages;
      private pagesChanged: EventEmitter<Page[]> = new EventEmitter<Page[]>();
    
      constructor(private location: Location, private router: Router) {
        this.setPagesFullPath();
        console.log(this.pages);
      }
    .
    .
    .
    
    }
    

    "test-one.component.ts"

    import { Page, PageData } from './../../core/models/page.model';
    import { PagesService } from './../../core/services/pages.service';
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-test-one',
      templateUrl: './test-one.component.html',
      styleUrls: ['./test-one.component.scss']
    })
    export class TestOneComponent implements OnInit {
      testATwoPage: Page;
    
      constructor(private pagesService: PagesService) {
      }
    
      ngOnInit() {
        this.testATwoPage = this.pagesService.getPageByTitle('Test A two');
      }
    
    }
    

    I'd love to know how I could resolve this circular dependency without having to dispense with any functionalities.

    Thanks in advance!