I get an error on my Angular app kind of a stackOverflow. (see updates at the end)
Basically my component is a diagram that includes two components. The equipment component that includes the equipment information and the socket component, that includes the type of connections that each equipment has. The socket component basically displays a dropdown with the equipment available to connect.
The "container" component basically creates a socket component with the type "start element" so we have a "fake" connection to select a start element. From then we select a start element and we can keep feeding the diagram.
When I select the first "start element" (pic1) the corresponding equipment is loaded with its corresponding sockets (7 units). Then I select on one of the sockets one equipment (pic2) and the same, it is loaded with one unit, all good. Then I select one more equipment in the corresponding socket (pic3) and buum, the app crashes.

I get this error:
ERROR RangeError: Maximum call stack size exceeded
at refreshView (core.js:9461)
at refreshEmbeddedViews (core.js:10591)
at refreshView (core.js:9490)
at refreshComponent (core.js:10637)
at refreshChildComponents (core.js:9263)
at refreshView (core.js:9516)
at refreshEmbeddedViews (core.js:10591)
at refreshView (core.js:9490)
at refreshComponent (core.js:10637)
at refreshChildComponents (core.js:9263)
I made some console logs and at the click where the error happens, the first start element is rendered (ngOnInit), the second one as well and in the third one that I clicked, the Socket onInit and Equipment onInit are called with no end. So it seems that the equipment and the socket are calling themselves with no end.
I checked my app, and I call only two times the socket component. Once on the container component just to create the "start element" socket and then on the ngfor on EquipmentComponent. And regarding equipment, it is only called once in the whole app, once mySocket.element is selected and is not null, therefore the ngIf shows the component.
I only have one module app.module so here the same, there are no multiple calls to the components.
Here the socketcomponent:
import { Component, Input, OnInit } from '@angular/core';
import { Equipment } from 'src/app/model/Equipment';
import { Socket } from 'src/app/model/Socket';
import { EquipmentService } from 'src/app/services/equipment.service';
@Component({
selector: 'app-socket',
templateUrl: './socket.component.html',
styleUrls: ['./socket.component.css']
})
export class SocketComponent implements OnInit {
@Input() mySocket: Socket;
@Input() parentEquipment: Equipment;
myElements: Equipment[];
constructor( private _equipmentNewService:EquipmentService) { }
ngOnInit(): void {
console.log("Myparentequipment:", this.parentEquipment)
this.myElements = this._equipmentNewService.getListForGivenInput(this.mySocket.type);
}
loadEquipment(eq:Equipment){
this.mySocket.element = eq;
}
amIFirstConnection(){
return !this.amIOnlyConnection() && this.mySocket === this.parentEquipment.eqType.connections[0];
}
amILastConnection(){
return !this.amIOnlyConnection() && this.mySocket === this.parentEquipment.eqType.connections[this.parentEquipment.eqType.connections.length-1];
}
amIMiddleConnection(){
return !this.amIOnlyConnection() && !this.amIFirstConnection() && !this.amILastConnection();
}
amIOnlyConnection(){
return this.parentEquipment.eqType.connections.length===1
}
}
Here the html file:
<!-- this is just to create the diagram lines, ignore it! -->
<div *ngIf="mySocket.type !== 'Start Element'">
<div *ngIf="amIOnlyConnection()" class="d-flex someMarginTop">
<div class="smallSpacer schema"></div>
<div class="mainSpacer schema borderLeft"></div>
</div>
<div *ngIf="amIFirstConnection()" class="d-flex someMarginTop">
<div class="smallSpacer schema"></div>
<div class="mainSpacer schema borderLeft borderTop"></div>
</div>
<div *ngIf="amIMiddleConnection()" class="d-flex someMarginTop">
<div class="smallSpacer schema borderTop"></div>
<div class="mainSpacer schema borderTop borderLeft"></div>
</div>
<div *ngIf="amILastConnection()" class="d-flex someMarginTop">
<div class="smallSpacer schema borderTop"></div>
<div class="mainSpacer schema borderLeft"></div>
</div>
</div>
<!-- here we display the info -->
<div class="dropdown someMargin">
<button class="btn btn-outline-secondary btn-sm dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
{{mySocket.name}}...
</button>
<ul class="dropdown-menu listSocket" aria-labelledby="dropdownMenuButton1">
<li *ngFor="let item of myElements">
<div class="d-flex"><a class="dropdown-item" (click)="loadEquipment(item)"><span style="margin-right:5px">{{item.eqType.productNumber}}</span></a></div>
</li>
</ul>
<!-- and here the call to equipment -->
<div *ngIf="mySocket.element">
<app-equipment [equipment]="mySocket.element" [parentSocket]="this.mySocket"></app-equipment>
</div>
</div>
And now the equipment component:
import { Component, Input, OnInit } from '@angular/core';
import { Equipment } from 'src/app/model/Equipment';
import { Socket } from 'src/app/model/Socket';
@Component({
selector: 'app-equipment',
templateUrl: './equipment.component.html',
styleUrls: ['./equipment.component.css']
})
export class EquipmentComponent implements OnInit {
@Input() equipment: Equipment;
@Input() parentSocket: Socket;
constructor() {
}
ngOnInit(): void {
console.log("Myparentsocket:", this.parentSocket)
this.equipment.available = false;
}
removeMyselfFromSocket() {
this.parentSocket.element = null;
}
}
Here the html file:
<div class="someMargin somePadding col-md-auto border rounded eqContainer animated fadeIn fast">
<div style="float:right">
<button type="button" class="btn btn-outline-danger px-3" style="padding: 0px 7px !important;" (click)="removeMyselfFromSocket()"><i class="fas fa-trash fa-xs"></i></button>
</div>
<div class="d-flex">
<div>
<!-- <img [src]="equipment.eqType.img" class="img-fluid imgTestModel" [alt]="equipment.eqType.productNumber"> -->
</div>
<div style="margin-left:5px" class="bg-light border rounded somePadding" style="margin-right:30px">
<!-- <p class="title p-lessMargin text-primary">{{equipment.eqType.productNumber}}</p> -->
<p class="ids p-lessMargin">ProductNO: <span class="ids-content">ABC8493RT</span> </p>
<p class="ids p-lessMargin">SerialNO: <span class="ids-content">15698247896</span></p>
<p class="ids p-lessMargin">SwRev: <span class="ids-content">2.2.145</span></p>
</div>
</div>
<div class="d-flex">
<app-socket *ngFor="let socket of equipment.eqType.connections" [mySocket]="socket" [parentEquipment]="equipment"></app-socket>
</div>
</div>
I hope I attached enough information and I would be very happy to get some help!
Thanks in advance :)
Update 1: After changing on socket component this method (to avoid the change detector being called the whole time):
equipmentSelected:Equipment;
loadEquipment(eq:Equipment){
this.equipmentSelected = eq;
}
I can now add more childs to my tree. Now the question is, how can I do to keep the this.mySocket.element = eq? Otherwise I would lose my tree structure and would not be able to serialize my objects...