NG3003:库中的 Angular 12 循环依赖 - Ivy 部分编译模式

我提出了一个问题 here
我有一个 ParentComponent ,它有一个子 ChildComponent ,子里面有 ParentComponent ,所以这里有一个循环。
这是我面临的错误:

✖ Compiling with Angular sources in Ivy partial compilation mode.
ERROR: projects/api/src/lib/api.component.ts:3:1
error NG3003: One or more import cycles would need to be created to 
compile this component, which is not supported by the current compiler
configuration.

The component 'ParentComponent' is used in the template but importing
it would create a cycle:
 /lib/child/child.component.ts -> /lib/parent/parent.component.ts -> /lib/child/child.component.ts

此错误仅发生在 Angular 库中。如您所见, stackblitz 示例中没有问题,这只是一个演示。

在库的 "compilationMode": "full" 文件中设置 tsconfig.lib.prod.json 会消除此错误,但在这种情况下,我们会失去向后兼容性! 😕

官方文档说:

将相互引用的类移动到同一个文件中,以避免它们之间的任何导入。块引用

它有效,但这确实是一种丑陋的方式!此外,我们有很多组件,我们就是做不到!

你能帮我吗?!
enter image description here

stack overflow NG3003: Angular 12 Circular Dependency in library - Ivy partial compilationMode
原文答案
author avatar

接受的答案

好的,在网上找遍了,我终于自己解决了!
我使用了这篇文章建议的动态方法:
Angular Circular Dependencies with Dynamic Nested Components
您可以在 stackblitz 中查看我的解决方案。
我必须在这里再次提到这个问题( NG3003 )只发生在具有 partial 编译模式的 Angular 库 中。

所以我之前提到的帖子不是一个完整的解决方案和一个工作示例。我添加的是一个名为 ComponentStructure 的接口:

export interface ComponentStructure {
  type: string;
  content: {
    textContent: string;
    components: ComponentStructure[];
  };
}

并且 components 输入到父组件和子组件:

import { Component, Input } from '@angular/core';
import { Base } from '../base';
import { HtmlComponent } from '../child-node.directive';
import { ComponentStructure } from '../component-structure';

@HtmlComponent({ map: ['lib_parent'] })
@Component({
    selector: 'lib-parent',
    templateUrl: './parent.component.html',
  ],
})
export class ParentComponent extends Base {
  @Input() count = 3;
  @Input() set components(_components: ComponentStructure[]) {
    this.childNodes = _components;
  }
  public textContent: string = '';

  constructor() {
    super();
  }

  set content(content: any) {
    this.textContent = content.textContent;
    this.components = content.components;
  }
}

我也改变了 Base 类如下:

import { Directive, QueryList, ViewChildren } from '@angular/core';
import { interval } from 'rxjs';
import { take } from 'rxjs/operators';
import { ChildNodeDirective } from './child-node.directive';
import { ComponentStructure } from './component-structure';

@Directive()
export abstract class Base {
  // These are elements that the template will render into the directive
  @ViewChildren(ChildNodeDirective) protected children?: QueryList<any>;
  public childNodes: ComponentStructure[] = [];
  private childrenLoaded = false;

  ngAfterViewInit(): void {
    interval(10)
      .pipe(take(5))
      .subscribe(() => {
        if (!this.childrenLoaded && this.children) {
          this.children.forEach((child: ChildNodeDirective) => {
            child.load();
          });
          this.childrenLoaded = true;
        }
      });
  }
}

我不喜欢的是 interval 这是棘手的部分。但是原始答案中使用的 AfterContentChecked 对我不起作用,我必须这样做。
如果您对此有更好的想法,请在评论中告诉我🙃


答案:

作者头像

您好,这是老话题,但我搜索了很长时间的解决方案。我找到了您的解决方案,但并没有说服我。所以这就是我的解决方案。

正如您在回复中提到的,问题是像这张图片显示的那样,在孩子中导入了父母。 problem circular deps schema

导入在 html 中由 yo 使用的标记隐含。

这个概念并不是说 Angular 它是已知组件的导入。为此:在 chilComponent.ts 中:

@Input() parentComponentType;
@ViewChild('id', {read: ViewContainerRef, static: false}) container: ViewContainerRef;

ngAfterViewInit() {
    const formGen = this.container.createComponent(this.parentComponentType);
    formGen.setInput('someInputToSet', someValue);
  }

在 ChildComponent.html 中替换

<parent></parent>

经过

<div #id></div>

这段代码将采取

它用于在输入 parentComponentType 中传递组件并在您之前替换的 div 中创建它。

在 parent.html 中将输入指令 [parentComponentType] 添加到您的组件选择器:

<child [parentComponentType]="thisComponentType" >

在 parent.ts 中设置变量 thisComponentType thisComponentType = ParentComponent;