I have a angular component that uses ngAfterViewInit the first time I am on the page that uses the component and I click the button the ngAfterViewInit calls the method this.updateListSecondTable() once. When I leave the page and comme back the ngAfterViewInit calls the method this.updateListSecondTable() twice when I leave and come back a third time it calls the method tree times and so on why is this the case? Thank you for your help.
export class PurchaseReceptionsComponent implements OnInit, OnDestroy {
dtOptionsPurchaseReceptions: DataTables.Settings = {};
dtOptionsReceptionsConfirmed: DataTables.Settings = {};
public selectAll: boolean = false;
public lstPurchases: number[] = [];
public lstPurchasesRecived: number[] = [];
constructor(private renderer: Renderer2,
private router: Router,
private toastr: ToastrService,
private http: HttpClient,
private translate: TranslateService,
private purchaseService: PurchaseService) { }
ngOnInit(): void {
var token = localStorage.getItem("token");
this.dtOptionsPurchaseReceptions = {
ajax: {
url: this.purchaseService.getPurchasesRecptionsForDatatable(),
type: "GET",
dataType: "json",
headers: { "Authorization": "Bearer " token }
},
columns: [
{
render: function (data: any, type: any, row: any) {
return '<input type="checkbox" name = "purchasecheck" id="move-purchase-id' row.PurchaseId '" move-purchase-id="' row.PurchaseId '" value="' row.PurchaseId '" >';
}
},
{
data: 'Supplier.Name'
},
{
render: function (data: any, type: any, row: any) {
if (row.Contract != undefined) {
return '<a href="/contract/' row.Contract.ContractNumber '/search" target="_blank">' row.Contract.ContractNumber '</a>';
}
return '';
}
},
{
data: 'OrderNumber'
},
{
data: 'SupplierOrderNumber'
},
{
data: 'Component.Brand'
},
{
data: 'Component.Designation'
},
{
data: 'Component.Type'
},
{
data: 'Component.Reference'
},
{
data: 'Term'
},
{
data: 'OrderQuantity'
},
{
data: 'DeliveredQuantity'
},
{
data: 'UnitPrice'
},
{
data: 'OrderQuantity'
},
],
destroy: true,
pagingType: 'full_numbers',
pageLength: 10,
order: [[1, 'asc']],
columnDefs: [{
defaultContent: '',
targets: [0],
searchable: false,
orderable: false,
className: 'no-marking',
width: "25px"
},
{
defaultContent: '',
targets: [2]
}]
};
this.dtOptionsReceptionsConfirmed = {
destroy: true,
pagingType: 'full_numbers',
pageLength: 10,
columnDefs: [{
defaultContent: '',
targets: [1]
}]
};
this.getAllPurchaseReceptionsId();
}
ngOnDestroy() {
this.lstPurchases = [];
this.lstPurchasesRecived = [];
this.selectAll = false;
this.dtOptionsPurchaseReceptions = {}
this.dtOptionsReceptionsConfirmed = {}
}
ngAfterViewInit(): void {
this.renderer.listen('document', 'click', (event) => {
if (event.target.hasAttribute("move-purchase-id")) {
var purchaseIdNotFormated: string = event.target.getAttribute("move-purchase-id");
var purchaseId: number = Number(purchaseIdNotFormated.replace("move-purchase-id", ""));
this.updateListSecondTable(purchaseId);
}
});
}
}
CodePudding user response:
The description of this issue is textbook memory leak. You should make sure you don't leave references to this component hanging around and preventing it from being properly destroyed and cleaned up. My advice is to start handling the renderer.listen
thing more carefully.
Looking at the docs, it seems that it returns An "unlisten" function for disposing of this handler.
This means that you can capture the return value of the listen
call and keep it around to dispose of the handler inside onDestroy
:
export class PurchaseReceptionsComponent implements OnInit, OnDestroy {
// ...
private unlisten: (() => void) | null = null;
ngAfterViewInit(): void {
this.unlisten = this.renderer.listen('document', 'click', (event) => {
// ...
});
}
ngOnDestroy() {
// ...
this.unlisten?.();
}
}