ПРЕДУПРЕЖДЕНИЕ в обнаруженной круговой зависимости - Angular 9 - PullRequest
1 голос
/ 27 мая 2020

Я получил это предупреждение и не могу его решить.

Проблема связана с ComponentFactoryResolver в создаваемом мной модальном окне.

Полное предупреждение:

WARNING in Circular dependency detected:
projects/admin-panel/src/app/form/components/form-fields-modal/form-fields-modal.component.ts -> projects/admin-panel/src/app/form/components/annotation/annotation.component.ts -> projects/admin-panel/src/app/form/components/form-fields-modal/form-fields-modal.component.ts

Мои компоненты:

Annotation.component:

import { Component, OnInit, ElementRef, AfterViewInit, Input, EventEmitter, Output } from '@angular/core';
import { FormFieldsModalComponent } from '../form-fields-modal/form-fields-modal.component';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { FormFields } from '../../models/form-fields.model';

@Component({
  selector: 'app-annotation',
  templateUrl: './annotation.component.html',
  styleUrls: ['./annotation.component.scss']
})
export class AnnotationComponent implements OnInit, AfterViewInit {
  @Input() field: FormFields;
  @Input() position: any;

  @Output() fieldsUpdated = new EventEmitter<FormFields>();
  isResizing = false;
  _isDragging = false;

  annotationPosition = { x: 300, y: 100 };
  private minimumSize = 20;
  private annotationWidth = 0;
  private annotationHeight = 0;
  private elementPositionX = 0;
  private elementPositionY = 0;
  private mouseX = 0;
  private mouseY = 0;
  private _resizeMouseEventMove: (event: MouseEvent) => void;
  private _resizeMouseEventUp: (event: MouseEvent) => void;

  constructor(private elementRef: ElementRef,
              private _modalService: NgbModal) { }

  ngOnInit(): void {
  }

  ngAfterViewInit(): void {
    this.makeResizableDiv(this.elementRef.nativeElement.firstChild);
  }

  onDragEnded(event) {
    console.log('drag end');
    // this._isDragging = false;
    this.annotationPosition = event.source.getFreeDragPosition();
    this.field.positionX =  this.annotationPosition.x;
    this.field.positionY = this.annotationPosition.y;
    const fieldsUpdated = new FormFields();
    fieldsUpdated.positionX = this.annotationPosition.x;
    fieldsUpdated.positionY = this.annotationPosition.y;
    this.fieldsUpdated.emit(fieldsUpdated);
    console.log(`Annotation dragged: position x: ${this.annotationPosition.x} position y: ${this.annotationPosition.y}`);
    this._isDragging = false;
  }

  makeResizableDiv(element) {
    const resizers = element.querySelectorAll('.resizer');
    resizers.forEach(resizer => {
      resizer.addEventListener('mousedown', (event: MouseEvent) => {
        this.calculateResizerAttributes(event, element);

        this._resizeMouseEventMove = (evt: MouseEvent) => this.resize(evt, element, resizer);
        window.addEventListener('mousemove', this._resizeMouseEventMove);

        this._resizeMouseEventUp = (evt: MouseEvent) => this.stopResizing(element);
        window.addEventListener('mouseup', this._resizeMouseEventUp);
        // window.addEventListener('mouseup', (ev: MouseEvent) => this.stopResizing(element));
      });
    });
  }

  calculateResizerAttributes(event: MouseEvent, element) {
    this.annotationWidth = parseFloat(getComputedStyle(element, null).getPropertyValue('width').replace('px', ''));
    this.annotationHeight = parseFloat(getComputedStyle(element, null).getPropertyValue('height').replace('px', ''));
    this.elementPositionX = element.offsetLeft;
    this.elementPositionY = element.offsetTop;
    this.mouseX = event.pageX;
    this.mouseY = event.pageY;
    this.isResizing = true;
  }

  resize(event: MouseEvent, element?, resizer?) {
    if (!this.isResizing) {
      return;
    }

    if (resizer.classList.contains('bottom-right')) {
      console.log('bottom-right');
      const width = this.annotationWidth + (event.pageX - this.mouseX);
      const height = this.annotationHeight + (event.pageY - this.mouseY);
      if (width > this.minimumSize) {
        element.style.width = width + 'px';
        element.style.right = this.elementPositionX + (event.pageX - this.mouseX) + 'px';
        this.field.width = width;
      }
      if (height > this.minimumSize) {
        element.style.height = height + 'px';
        this.field.height = height;
      }
    } else if (resizer.classList.contains('bottom-left')) {
      const height = this.annotationHeight + (event.pageY - this.mouseY);
      const width = this.annotationWidth - (event.pageX - this.mouseX);
      if (width > this.minimumSize) {
        element.style.width = width + 'px';
        element.style.left = this.elementPositionX + (event.pageX - this.mouseX) + 'px';
        this.field.width = width;
        // Get TranslateX value for compute the position x after resizing
        const elementStyle = window.getComputedStyle(element);
        // tslint:disable-next-line: deprecation
        const translateX = new WebKitCSSMatrix(elementStyle.webkitTransform);
        this.field.positionX = translateX.m41 + parseInt(element.style.left, 10);
      }
      if (height > this.minimumSize) {
        element.style.height = height + 'px';
        this.field.height = height;
      }
    } else if (resizer.classList.contains('top-right')) {
      const width = this.annotationWidth + (event.pageX - this.mouseX);
      const height = this.annotationHeight - (event.pageY - this.mouseY);
      if (width > this.minimumSize) {
        element.style.width = width + 'px';
        this.field.width = width;
      }
      if (height > this.minimumSize) {
        element.style.height = height + 'px';
        element.style.top = this.elementPositionY + (event.pageY - this.mouseY) + 'px';
        this.field.height = height;
        const elementStyle = window.getComputedStyle(element);
        // tslint:disable-next-line: deprecation
        const translateY = new WebKitCSSMatrix(elementStyle.webkitTransform);
        this.field.positionY = translateY.m42 + parseInt(element.style.top, 10);

      }
    } else {
      const width = this.annotationWidth - (event.pageX - this.mouseX);
      const height = this.annotationHeight - (event.pageY - this.mouseY);
      if (width > this.minimumSize) {
        element.style.width = width + 'px';
        element.style.left = this.elementPositionX + (event.pageX - this.mouseX) + 'px';
        this.field.width = width;
         // Get TranslateX value for compute the position x after resizing
        const elementStyle = window.getComputedStyle(element);
         // tslint:disable-next-line: deprecation
        const translateX = new WebKitCSSMatrix(elementStyle.webkitTransform);
        this.field.positionX = translateX.m41 + parseInt(element.style.left, 10);
      }
      if (height > this.minimumSize) {
        element.style.height = height + 'px';
        element.style.top = this.elementPositionY + (event.pageY - this.mouseY) + 'px';
        this.field.height = height;
        const elementStyle = window.getComputedStyle(element);
        // tslint:disable-next-line: deprecation
        const translateY = new WebKitCSSMatrix(elementStyle.webkitTransform);
        this.field.positionY = translateY.m42 + parseInt(element.style.top, 10);
      }
    }
  }

  stopResizing(event: MouseEvent) {
    this.isResizing = false;
    window.removeEventListener('mousemove', this._resizeMouseEventMove);
    window.removeEventListener('mouseup', this._resizeMouseEventUp);
    const fieldUpdated = new FormFields();
    fieldUpdated.width = this.field.width;
    fieldUpdated.height = this.field.height;
    fieldUpdated.positionY = this.field.positionY;
    fieldUpdated.positionX = this.field.positionX;
    this.fieldsUpdated.emit(fieldUpdated);
  }

  openFormFieldsModal() {
    const modalRef = this._modalService.open(FormFieldsModalComponent, { windowClass: 'form-fields', centered: true, size: 'xl' });
    modalRef.componentInstance.field = this.field;
  }
}

form-fields-modal.component:

import { Component, OnInit, ElementRef, Input, ApplicationRef, ComponentFactoryResolver, Injector } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { FormFields } from '../../models/form-fields.model';
import { FormFieldsFacade } from '../../form-fields.facade';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ActivatedRoute } from '@angular/router';
import { AnnotationComponent } from '../annotation/annotation.component';

interface OptionField {
  position: number;
  name: string;
  positionX: number;
  positionY: number;
  width: number;
  height: number;
}

@Component({
  selector: 'app-form-fields-modal',
  templateUrl: './form-fields-modal.component.html',
  styleUrls: ['./form-fields-modal.component.scss']
})
export class FormFieldsModalComponent implements OnInit {
  @Input() field: FormFields;
  fieldsGroup: FormGroup;

  constructor(private elementRef: ElementRef,
              private _formBuilder: FormBuilder,
              private _formFieldsFacade: FormFieldsFacade,
              private _activeModal: NgbActiveModal,
              private _app: ApplicationRef,
              private _factoryResolver: ComponentFactoryResolver,
              private _injector: Injector) { }

  ngOnInit(): void {
    this._setupFormBuilder();
    this.fieldsGroup.setValue({
      name: this.field.name,
      type: this.field.type,
      description: this.field.description,
      note: this.field.note,
    });
  }

  // Setup
  private _setupFormBuilder() {
    this.fieldsGroup = this._formBuilder.group({
      name: ['', Validators.required],
      type: ['', Validators.required],
      description: ['', Validators.required],
      note: ['', Validators.required],
    });
  }

  onSubmitFormButtonClicked() {
    const field = new FormFields();
    field.name = this.fieldsGroup.get('name').value;
    field.type = this.fieldsGroup.get('type').value;
    field.description = this.fieldsGroup.get('description').value;
    field.note = this.fieldsGroup.get('note').value;
    this._formFieldsFacade.updateFormFields(field, this.field.id);
  }

  onCancelFormButtonClicked() {
    this._activeModal.close();
  }

  addOptionField() {
    console.log('append option');
    const container = document.querySelector('.ng2-pdf-viewer-container') as HTMLElement;
    const currentPage = document.querySelector(`.page[data-page-number='${this.field.formPage}']`) as HTMLElement;
    if (container === null || currentPage === null) {
      return;
    }

    // const topBoundry = parentAnnotation.scrollTop;
    // const position = {
    //   x: 10,
    //   y: topBoundry + 10
    // };

    // Create a annotation object
    const optionField: OptionField = {
      position: 1,
      name: 'בדיקה',
      positionX: this.field.positionX ,
      positionY: this.field.positionY,
      width: 25,
      height: 25
    };


    this._appendOptionField(optionField, true);
  }


 private _appendOptionField(fields: FormFields, isNew: boolean) {
    const factory = this._factoryResolver.resolveComponentFactory(AnnotationComponent);
    const annotationElement = document.createElement('div');
    annotationElement.className = 'option-annotation';
    document.getElementById('annotation-' + this.field.id).appendChild(annotationElement);
    const ref = factory.create(this._injector, [], annotationElement);
    ref.instance.field = fields;
    ref.instance.position = { x: fields.positionX, y: fields.positionY };
    this._app.attachView(ref.hostView);
  }


}

Когда я удаляю преобразователь фабрики компонентов, предупреждение исчезает, но Мне это нужно.

Я загружаю данные в модальное окно из компонента аннотации, а затем мне нужно манипулировать dom и добавлять элементы в компонент аннотации.

1 Ответ

0 голосов
/ 27 мая 2020

Итак, почему это происходит:

То, что из экземпляра поля формы вы ссылаетесь на аннотацию, а от аннотации обратно к компоненту из поля формы

Форма -> Аннотация -> Поле формы.

Сделайте что-то одно, создайте промежуточную службу для обращения к ним.

Форма -> Услуга -> Аннотация

Аннотация -> Услуга -> Форма

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...