Обойти круговую зависимость

#angular #circular-dependency

#угловатый #циклическая зависимость

Вопрос:

Есть ли лучший способ обойти циклическую зависимость, если компонент использует службу, а служба инициализирует компонент? что я здесь сделал, так это то, что, поскольку компонент инициализируется службой, я внедряю саму службу в компонент без использования внедрения угловых зависимостей.

Служба рабочего пространства

 @Injectable()
export class WorkspaceService {
  name = "John";
  constructor(
    private cfr: ComponentFactoryResolver,
    private appRef: ApplicationRef,
    private injector: Injector
  ) {
    this.appendWorkspaceToBody();
  }

  private appendWorkspaceToBody(): void {
    const workspaceRef = this.cfr
      .resolveComponentFactory(WorkspaceComponent)
      .create(this.injector);
    workspaceRef.instance.workspaceService = this;

    this.appRef.attachView(workspaceRef.hostView);

    const domElem: HTMLElement = (workspaceRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;

    document.body.appendChild(domElem);
  }
}
 

Компонент рабочей области

 @Component({
  selector: "app-workspace",
  template: "{{workspaceService.name}}"
})
export class WorkspaceComponent implements OnInit {
  public workspaceService: WorkspaceService

  ngOnInit() {}
}
 

Чтобы проверить код проблемы, перейдите в stackblitz

Комментарии:

1. Вместо того, чтобы импортировать класс внутри службы, почему вы не можете передать в качестве аргумента appendWorkspaceToBody ?

2. что это изменит, поскольку оно вызывается только из своего конструктора

3. Да, это избавит от ошибки циклической зависимости. И вы должны вызвать его из компонента, вместо того, чтобы вызывать внутреннюю службу

4. тем не менее я получаю предупреждение о сборке для циклической зависимости

5. Я пробовал в stackblitz, это работает fine:stackblitz.com/edit/angular-ivy-qeqimh?file=src/app/workspace /…

Ответ №1:

Лучшее решение, которое я нашел для этой проблемы, — написать отдельную службу для инициализации компонента, которая выполняется из модуля путем предоставления в APP_INITIALISER .

Модуль

 // @dynamic
@NgModule({
  imports: [BrowserModule, FormsModule],
  declarations: [AppComponent, HelloComponent, WorkspaceComponent],
  bootstrap: [AppComponent],
  providers: [
    WorkspaceService,
    WorkspaceInitializeService,
    {
      provide: APP_INITIALIZER,
      useFactory: (service: WorkspaceInitializeService) => () =>
        service.appendWorkspaceToBody(),
      multi: true,
      deps: [WorkspaceInitializeService]
    }
  ]
})
export class AppModule {}
 

Обслуживание

 @Injectable()
export class WorkspaceService {
  name = "John";
  constructor() {
  }
}
 

Служба инициализации

 @Injectable()
export class WorkspaceInitializeService {
  constructor(
    private cfr: ComponentFactoryResolver,
    private injector: Injector
  ) {}
  appendWorkspaceToBody(): void {
    const workspaceRef = this.cfr
      .resolveComponentFactory(WorkspaceComponent)
      .create(this.injector);

    this.injector.get(ApplicationRef).attachView(workspaceRef.hostView);

    const domElem: HTMLElement = (workspaceRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;

    document.body.appendChild(domElem);
  }
}
 

Чтобы проверить код решения, перейдите в stackblitz