Angular 6+: при условии, что некорневой модуль вызывает циклическую зависимость

Я пытаюсь предоставить услугу разрешения через новый providedIn атрибут.

Это преобразователь переводов, который я использую в защищенном модуле:

import { Injectable } from '@angular/core';

import { Observable , pipe } from 'rxjs';
import {map} from "rxjs/operators";

//This is causing: "WARNING in Circular dependency detected:"
import {ProtectedModule} from "../../../protected/protected.module";

import { HttpHandlerService } from '../../http/http-handler.service';

@Injectable({
  providedIn: ProtectedModule //Over here (I need the import for this line)
})
export class TranslationsResolverService {
  constructor(private _httpHandlerService : HttpHandlerService) { }
    resolve(): any {
      //Do Something...
    }
}

Ответ 1

Это не проблема угловых зависимостей.

Циклическая ссылка генерируется компилятором TypeScript при попытке разрешить циклический импорт.

Первое решение

Создайте новый модуль с именем ProtectedResolversModule и используйте providedIn: ProtectedResolversModule и переместите там резольверы.

Теперь вы можете импортировать этот модуль в ProtectedModule и при загрузке ProtectedRoutingModule вы не получите ошибку круговой зависимости.

Второе решение

Используйте массив providers ProtectedModule.

Ответ 2

Я столкнулся с той же проблемой. Оказывается, решение "не делай этого", как объяснил в этой теме один из парней из Angular: https://github.com/angular/angular-cli/issues/10170#issuecomment-380673276

Это сводится к тому, что сервисам легче встряхнуть дерево, когда они предоставляются корневым модулем, насколько я понимаю.

Я так же разочарован, как и вы.

Ответ 3

Я думаю, что Angular немного напутал в синтаксисе providedIn. Кажется, это смутило многих людей. Например. увидеть эти две темы GitHub:

Синтаксис providedIn, похоже, имеет 2 основных преимущества:

  1. Поддерживается тряска деревьев неиспользуемых сервисов
  2. providedIn: 'root' гарантирует, что вы получите только один экземпляр службы

Но вам действительно нужно (1), если вы пишете библиотеку, а не приложение (потому что зачем вам включать в приложение службу, которая вам не нужна), и вы можете избежать нескольких экземпляров службы (2) просто убедитесь, что вы не импортировали сервисный модуль более одного раза.

Проблемы с синтаксисом providedIn:

  1. providedIn: 'root' разрывает связь между службой и модулем, в котором он "живет" (или "с") - потому что служба не знает о модуле, а модуль не знает о службе. Это означает, что сервис больше не "принадлежит" этому модулю и будет просто связан с тем, что на него ссылается. Это, в свою очередь, означает, что теперь потребитель сервиса должен убедиться, что инъекционные зависимости сервиса (если они есть) доступны до его использования, что вводит в заблуждение и довольно нелогично.
  2. Задача циклической ссылки описана выше. На самом деле невозможно - с помощью этого синтаксиса - сохранить связь между службой и ее модулем, если служба фактически используется какими-либо компонентами в том же модуле.

Это противоречит официальному руководству Angular, но мой совет: Не используйте providedIn, если только вы не пишете стороннюю библиотеку, которая требует встряхивания деревьев - используйте старую (не рекомендуется) providers вместо этого синтаксис в модуле, а именно:

@NgModule({ providers: [MyService], })

Добавление

Я получил 5 голосов "за" за этот ответ, поэтому я чувствую, что должен прийти в себя и сказать, что больше не следую собственному совету по этому поводу!

Поскольку официальная (и широко используемая) политика Angular заключается в использовании providedIn: 'root', я решил, что в целом для других разработчиков было бы меньше путаницы, если бы я просто придерживался этого. До сих пор это не вызывало у меня никаких проблем, но вышеизложенные предостережения все еще остаются, и я считаю важным постоянно помнить об этом.

Ответ 4

Проверьте функцию forwardRef() из углового/ядро. Это позволяет ссылаться на ссылки, которые еще не определены.

import {MyService} from './service';

constructor(@Inject(forwardRef(() => MyService)) public myService: MyService) {
}