Búsqueda de sitios web

typescript - Dependencia Circular en el Módulo de Diálogo de Angular-Material


Estoy trabajando con Angular 8 y tengo un modal de inicio de sesión con un enlace al modal de registro, y viceversa. Ambos modales se abren desde el authService. El problema es que el authService necesita una referencia a los componentes de inicio de sesión y registro para poder abrirlos. Simplemente no puedo encontrar una manera de evitar la dependencia circular allí.

Busqué en Google y Stack Overflow y la mejor solución que encontré fue desactivar las advertencias de dependencia circular en el archivo angular.json, lo cual no es la solución que estoy buscando. Reduje los 3 archivos relevantes para mostrar solo el código pertinente. Todo funciona bien, solo quiero deshacerme del mensaje de error y no enfrentarme a problemas inesperados más adelante, y trato de averiguar cuál es la forma correcta de hacer esto.

export class AuthService {
  loginModalRef: MatDialogRef<LoginComponent>;
  signupModalRef: MatDialogRef<SignupComponent>;

  constructor(
    private dialog: MatDialog
    ) {}

  closeLoginModal(): void {
    this.loginModalRef.close();
  }

  closeSignupModal(): void {
    this.signupModalRef.close();
  }

  openLoginModal(): void {
    if (this.signupModalRef) {
      this.closeSignupModal();
    }
    this.loginModalRef = this.dialog.open(LoginComponent, {panelClass: 'login-dialog'});
  }

  openSignupModal(): void {
    if (this.loginModalRef) {
      this.closeLoginModal();
    }
    this.signupModalRef = this.dialog.open(SignupComponent, {panelClass: 'signup-dialog'});
  }
}


export class LoginComponent implements OnInit {
  loginForm: FormGroup;

  constructor(
    private authService: AuthService
  ) {}

//when user clicks on 'Signup instead'
  openSignupModal() {
    this.authService.openSignupModal();
  }
}



@Component({
  selector: 'app-signup',
  templateUrl: './signup.component.html',
  styleUrls: ['./signup.component.scss']
})
export class SignupComponent implements OnInit {
  constructor(
    private authService: AuthService
  ) {}

// when user clicks on 'Login instead'
  openLoginModal() {
    this.authService.openLoginModal();
  }

// when user clicks on 'Terms of Services' the modal closes
  closeSignupModal() {
    this.authService.closeSignupModal();
  }
}

Este es el mensaje de error:

ADVERTENCIA: se detectó dependencia cíclica: src\app\auth\auth.service.ts -> src\app\auth\login\login.component.ts -> src\app\auth\auth.service.ts

ADVERTENCIA se detectó una dependencia circular: src\app\auth\login\login.component.ts -> src\app\auth\auth.service.ts -> src\app\auth\login\login.component.ts

ADVERTENCIA: se detectó una dependencia circular: src\app\auth\signup\signup.component.ts -> src\app\auth\auth.service.ts -> src\app\auth\signup\signup.component.ts

Respuesta #1

Probablemente deberías reestructurar un poco tu aplicación aquí para que tus componentes de inicio de sesión y registro estén envueltos por un componente modal.

@Component({
  template: `<app-login></app-login>`
})
export class LoginModalComponent { .. whatever in here, maybe something useful .. }

entonces su servicio instanciaría el LoginModalComponent

this.loginModalRef = this.dialog.open(LoginModalComponent, {panelClass: 'login-dialog'});

esto evita la dependencia circular de LoginComponent -> AuthService y AuthService -> LoginComponent,

ahora es LoginModalComponent -> AuthService -> LoginComponent

Es probable que el componente contenedor también pueda tomar parte de la lógica dentro de tu componente de inicio de sesión para una mejor modularidad.

otra opción es una especie de servicio remoto que se inyecta en el servicio de autenticación y en el componente de inicio de sesión

@Injectable()
export class ModalRemoteService {
  private closeLoginSource = new Subject();
  closeLogin$ = this.closeLoginSource.asObservable();
  private openLoginSource = new Subject();
  openLogin$ = this.openLoginSource.asObservable();

  closeLoginModal(): void {
    this.closeLoginSource.next();
  }

  openLoginModal(): void {
    this.openLoginSource.next();
  }
}

y el servicio de autenticación se suscribe a estas señales y el componente de inicio de sesión/registro las activa, de esta manera ya no necesitas inyectar autenticación en inicio de sesión.

Generalmente tienes un problema estructural donde estás usando un servicio para instanciar y destruir componentes desde dentro de los componentes que debes resolver de alguna manera, generalmente con envoltorios o remotos.