Circular dependency with angular 13

911 Views Asked by At

i've been trying to build the library with angular 13 and im getting an circular dependency error:

The component 'TreeNodeChildrenComponent' is used in the template but importing it would create a cycle: D:/DATA_WINDOWS/documents/_projects/angular-tree-component/projects/angular-tree-component/src/lib/components/tree-node/tree-node.component.ts -> D:/DATA_WINDOWS/documents/_projects/angular-tree-component/projects/angular-tree-component/src/lib/components/tree-node-children/tree-node-children.component.ts -> D:/DATA_WINDOWS/documents/_projects/angular-tree-component/projects/angular-tree-component/src/lib/components/tree-node-collection/tree-node-collection.component.ts -> D:/DATA_WINDOWS/documents/_projects/angular-tree-component/projects/angular-tree-component/src/lib/components/tree-node/tree-node.component.ts

Any idea on how to solve this?

PS: If i build it with angular 11 i dont have any errors

https://stackblitz.com/edit/angular-ivy-fyvwvj?file=src/app/angular-tree-component.module.ts

UPDATE: i've ran madge to find the circular dependency and noticed that there is an issue also in the models.

Merged all models in a single file but the circular dependency continues on the components madge

1

There are 1 best solutions below

0
On BEST ANSWER

I was able to fix th issue by merging tree-node.component.ts, tree-node-children.component.ts and tree-node-collection.component.ts into a single file.

import {
  Component,
  ViewEncapsulation,
  Input,
  OnInit,
  OnDestroy
} from '@angular/core';
import {
  computed,
  action,
  reaction,
  observable
} from 'mobx';
import {
  TreeNode
} from '../../models/tree-node.model';
import {
  TreeVirtualScroll
} from '../../models/tree-virtual-scroll.model';
import {
  TreeModel
} from '../../models/tree.model';

@Component({
  selector: 'tree-node-collection',
  templateUrl: './tree-node-collection.component.html',
  encapsulation: ViewEncapsulation.None
})
export class TreeNodeCollectionComponent implements OnInit, OnDestroy {
  @Input()
  public get nodes() {
    return this._nodes;
  }
  public set nodes(nodes) {
    this.setNodes(nodes);
  }

  @Input() public treeModel: TreeModel;

  @observable public _nodes: any;
  private virtualScroll: TreeVirtualScroll; // Cannot inject this, because we might be inside treeNodeTemplateFull
  @Input() public templates: any;

  @observable public viewportNodes: TreeNode[];

  @computed public get marginTop(): string {
    const firstNode =
      this.viewportNodes && this.viewportNodes.length && this.viewportNodes[0];
    const relativePosition =
      firstNode && firstNode.parent ?
      firstNode.position -
      firstNode.parent.position -
      firstNode.parent.getSelfHeight() :
      0;

    return `${relativePosition}px`;
  }

  public _dispose: any[] = [];

  @action public setNodes(nodes: any) {
    this._nodes = nodes;
  }

  public ngOnInit() {
    this.virtualScroll = this.treeModel.virtualScroll;
    this._dispose = [
      // return node indexes so we can compare structurally,
      reaction(
        () => this.virtualScroll
        .getViewportNodes(this.nodes)
        .map((n: {
          index: any
        }) => n.index),
        nodeIndexes => {
          this.viewportNodes = nodeIndexes.map((i: string | number) => this.nodes[i]);
        }, {
          compareStructural: true,
          fireImmediately: true
        }
        as any
      ),
      reaction(
        () => this.nodes,
        nodes => {
          this.viewportNodes = this.virtualScroll.getViewportNodes(nodes);
        }
      )
    ];
  }

  public ngOnDestroy() {
    this._dispose.forEach(d => d());
  }

  public trackNode(node: {
    id: any
  }) {
    return node.id;
  }
}

@Component({
  selector: 'tree-node-children',
  encapsulation: ViewEncapsulation.None,
  templateUrl: './tree-node-children.component.html'
})

export class TreeNodeChildrenComponent {
  @Input() public node: TreeNode;
  @Input() public templates: any;
}

@Component({
  selector: 'TreeNode, tree-node',
  templateUrl: './tree-node.component.html',
  encapsulation: ViewEncapsulation.None
})
export class TreeNodeComponent {
  @Input() public node: TreeNode;
  @Input() public index: number;
  @Input() public templates: any;
}