Я получил это предупреждение и не могу его решить.
Проблема связана с 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 и добавлять элементы в компонент аннотации.