Skip to content

When NgModelService is injected and we destroy component that have inside a ng-diagram instance it throw errors: rror: [ngDiagram] Library engine not initialized yet. #466

@Filipstrozik

Description

@Filipstrozik

Hi! Thank You very much for all of your work ;)

when I was using ng-diagram in a popup dialog in fullscreen mode, I get across en unhandleded error about that:
`app.html:6 Error unregistering model listener: Error: [ngDiagram] Library engine not initialized yet.

To fix this, wait for initialization to complete using one of these methods:
• Use "isInitialized" signal from NgDiagramService
• Use "diagramInit" event handler passed to NgDiagramComponent

Documentation: https://www.ngdiagram.dev/docs/guides/model-initialization/#waiting-for-initialization

at _FlowCoreProviderService.provide (ng-diagram.mjs:6141:31)
at get flowCore (ng-diagram.mjs:6436:34)
at _NgDiagramModelService.ngOnDestroy (ng-diagram.mjs:10108:12)
at executeOnDestroys (debug_node.mjs:7483:32)
at cleanUpView (debug_node.mjs:7379:9)
at destroyViewTree (debug_node.mjs:7323:17)
at destroyLView (debug_node.mjs:7353:5)
at removeLViewFromLContainer (debug_node.mjs:9327:9)
at Module.ɵɵconditional (debug_node.mjs:22036:17)
at App_Template (app.html:6:3)`

When I close a dialog. So we just destroy the component which has an ng-diagram component instance inside.
What is funny it only throws when we have injected NgModelService inside the compononent. Yeah and I need the modelService for later use to change the diagram data inside.

Also I have struggled with auto zooming to fit after modelService.addNodes() method, it somhow is async and it calculates the zoom and viewport while new nodes are still not added. - but maybe it's a different issue :)

code snippets:

app.html

`<button (click)="closeDiagram()">Close diagram

@if(showDiagram()){ }
` app.ts `Close diagram
@if(showDiagram()){ }
`

diagram.html

@if (model()){ <ng-diagram [model]="model()" [nodeTemplateMap]="nodeTemplateMap" [config]="config" /> }

diagram.ts

`import {
Component,
inject,
effect,
signal,
Injector,
OnDestroy,
} from '@angular/core';
import { delay, takeUntil } from 'rxjs/operators';
import { of, Subject } from 'rxjs';
import {
NgDiagramComponent,
NgDiagramConfig,
NgDiagramModelService,
NgDiagramNodeTemplateMap,
initializeModel,
provideNgDiagram,
} from 'ng-diagram';
import { NodeComponent } from '../diagram-node/diagram-node';

enum NodeTemplateType {
CustomNodeType = 'customNodeType',
}

@component({
selector: 'app-diagram',
standalone: true,
imports: [NgDiagramComponent],
providers: [provideNgDiagram()],
templateUrl: './diagram.html',
styleUrl: './diagram.scss',
})
export class Diagram implements OnDestroy {
private modelService = inject(NgDiagramModelService);
private injector = inject(Injector);
private destroy$ = new Subject();

nodeTemplateMap = new NgDiagramNodeTemplateMap([
[NodeTemplateType.CustomNodeType, NodeComponent],
]);

model = signal(null);

config = {
edgeRouting: {
defaultRouting: 'bezier',
},
zIndex: {
edgesAboveConnectedNodes: true,
},
zoom: {
zoomToFit: {
onInit: true,
},
},
debugMode: true,
} satisfies NgDiagramConfig;

constructor() {
effect(() => {
this.initializeModelFromApi();
});
}

ngOnDestroy(): void {
try {
this.model.set(null);
this.destroy$.next();
this.destroy$.complete();
} catch (error) {
console.warn('Error removing diagram event listeners:', error);
}
}

private initializeModelFromApi() {
// Mimic API call with 2 second delay
of(this.onAddNodesAndEdges())
.pipe(delay(2000), takeUntil(this.destroy$))
.subscribe((data) => {
this.model.set(initializeModel(data, this.injector));
});
}

onAddNodesAndEdges() {
const nodes = [
{ id: '1', position: { x: 200, y: 250 }, data: { label: 'Node 1' } },
{ id: '2', position: { x: 300, y: 350 }, data: { label: 'Node 2' } },
{ id: '3', position: { x: 600, y: 450 }, data: { label: 'Node 3' } },
];

const edges = [
  {
    id: '1',
    source: '1',
    sourcePort: 'port-right',
    targetPort: 'port-left',
    target: '2',
    data: {},
  },
  {
    id: '2',
    source: '2',
    sourcePort: 'port-right',
    targetPort: 'port-left',
    target: '3',
    data: {},
  },
];

return {
  nodes,
  edges,
};

}
}
`
screenshots:

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions