Skip to content

Commit 0a42b98

Browse files
refactor/AB#82357_update-angular-fix-memory-leak-issues-and-other-fixes fix: add missing timeout teardown logic
1 parent 9d1ffb9 commit 0a42b98

File tree

9 files changed

+62
-14
lines changed

9 files changed

+62
-14
lines changed

libs/shared/src/lib/components/geospatial-map/geospatial-map.component.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,6 @@ export class GeospatialMapComponent
133133
*/
134134
private disableGeomanToolsFlag = false;
135135

136-
// output
137-
/**
138-
* Timeout for the reverse search
139-
*/
140-
private timeout: ReturnType<typeof setTimeout> | null = null;
141136
/**
142137
* Output for the map change
143138
*/

libs/shared/src/lib/components/ui/map/map-popup/map-popup.service.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,15 @@ export class MapPopupService {
9696
}
9797
// We will bind and unbind each time we set the popup for dynamic purposes
9898
layerToBind?.unbindPopup();
99+
if (this.timeoutListener) {
100+
clearTimeout(this.timeoutListener);
101+
}
99102
instance.destroy();
100103
});
101104
if (this.timeoutListener) {
102105
clearTimeout(this.timeoutListener);
103106
}
104-
setTimeout(() => {
107+
this.timeoutListener = setTimeout(() => {
105108
// Reset default popup
106109
if (this.popupPane) {
107110
this.popupPane.className = 'leaflet-pane leaflet-popup-pan';

libs/shared/src/lib/components/widgets/editor/editor.component.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
HostListener,
88
Renderer2,
99
ElementRef,
10+
OnDestroy,
1011
} from '@angular/core';
1112
import { SafeHtml } from '@angular/platform-browser';
1213
import { Apollo } from 'apollo-angular';
@@ -46,7 +47,10 @@ import { Router } from '@angular/router';
4647
templateUrl: './editor.component.html',
4748
styleUrls: ['./editor.component.scss'],
4849
})
49-
export class EditorComponent extends UnsubscribeComponent implements OnInit {
50+
export class EditorComponent
51+
extends UnsubscribeComponent
52+
implements OnInit, OnDestroy
53+
{
5054
/** Widget settings */
5155
@Input() settings: any;
5256
/** Should show padding */
@@ -685,4 +689,11 @@ export class EditorComponent extends UnsubscribeComponent implements OnInit {
685689
);
686690
}
687691
}
692+
693+
override ngOnDestroy(): void {
694+
super.ngOnDestroy();
695+
if (this.timeoutListener) {
696+
clearTimeout(this.timeoutListener);
697+
}
698+
}
688699
}

libs/shared/src/lib/components/widgets/summary-card/summary-card-item-content/summary-card-item-content.component.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
HostListener,
55
Input,
66
OnChanges,
7+
OnDestroy,
78
OnInit,
89
Optional,
910
Renderer2,
@@ -32,7 +33,7 @@ import { Router } from '@angular/router';
3233
})
3334
export class SummaryCardItemContentComponent
3435
extends UnsubscribeComponent
35-
implements OnInit, OnChanges
36+
implements OnInit, OnChanges, OnDestroy
3637
{
3738
/** Html template */
3839
@Input() html = '';
@@ -261,4 +262,11 @@ export class SummaryCardItemContentComponent
261262
});
262263
}
263264
}
265+
266+
override ngOnDestroy(): void {
267+
super.ngOnDestroy();
268+
if (this.timeoutListener) {
269+
clearTimeout(this.timeoutListener);
270+
}
271+
}
264272
}

libs/shared/src/lib/services/download/download.service.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ const SNACKBAR_DURATION = 3000;
3232
providedIn: 'root',
3333
})
3434
export class DownloadService {
35+
/** Save file timeout listener */
36+
private saveFileTimeoutListener!: NodeJS.Timeout;
37+
3538
/**
3639
* Shared download service. Handles export and upload events.
3740
* TODO: rename in file service
@@ -234,7 +237,10 @@ export class DownloadService {
234237
link.download = fileName;
235238
this.document.body.append(link);
236239
link.click();
237-
setTimeout(() => link.remove(), 0);
240+
if (this.saveFileTimeoutListener) {
241+
clearTimeout(this.saveFileTimeoutListener);
242+
}
243+
this.saveFileTimeoutListener = setTimeout(() => link.remove(), 0);
238244
}
239245

240246
/**

libs/shared/src/lib/services/editor/editor.service.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export class EditorService {
1919
private editorScrollListener!: any;
2020
/** Active item scroll listener */
2121
public activeItemScrollListener!: any;
22+
/** Allow scrolling timeout listener */
23+
private allowScrollingTimeoutListener!: NodeJS.Timeout;
2224
/** Renderer */
2325
private renderer!: Renderer2;
2426

@@ -122,7 +124,10 @@ export class EditorService {
122124
if (this.editorScrollListener) {
123125
this.editorScrollListener();
124126
}
125-
setTimeout(() => {
127+
if (this.allowScrollingTimeoutListener) {
128+
clearTimeout(this.allowScrollingTimeoutListener);
129+
}
130+
this.allowScrollingTimeoutListener = setTimeout(() => {
126131
const autoCompleterContainer =
127132
this.document.querySelector('.tox-tinymce-aux');
128133
if (!autoCompleterContainer) return;

libs/shared/src/lib/services/map/map-controls.service.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ export class MapControlsService {
5555
private downloadControlClickListener!: any;
5656
/** Listener on download control wheel */
5757
private downloadControlWheelListener!: any;
58+
/** Address marker timeout listener */
59+
private addressMarkerTimeoutListener!: NodeJS.Timeout;
5860

5961
/**
6062
* Shared map control service
@@ -185,11 +187,19 @@ export class MapControlsService {
185187
<b>${'longitude: '}</b>${coordinates.lng}</p>`
186188
);
187189
circle.bindPopup(popup);
188-
popup.on('remove', () => map.removeLayer(circle));
190+
popup.on('remove', () => {
191+
if (this.addressMarkerTimeoutListener) {
192+
clearTimeout(this.addressMarkerTimeoutListener);
193+
}
194+
map.removeLayer(circle);
195+
});
189196
circle.openPopup();
190197
// Use setTimeout to prevent the marker to be removed while
191198
// the map moves to the searched address and is re-centred
192-
setTimeout(() => {
199+
if (this.addressMarkerTimeoutListener) {
200+
clearTimeout(this.addressMarkerTimeoutListener);
201+
}
202+
this.addressMarkerTimeoutListener = setTimeout(() => {
193203
this.addressMarker = circle;
194204
}, 1000);
195205
}

libs/shared/src/lib/services/map/map-polygons.service.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export class MapPolygonsService {
2727
private admin0sReady = new BehaviorSubject<boolean>(false);
2828
/** Admin0 polygons status as observable */
2929
public admin0sReady$ = this.admin0sReady.asObservable();
30+
/** Map fit bounds timeout listener */
31+
private fitBoundsTimeoutListener!: NodeJS.Timeout;
3032

3133
/**
3234
* Shared map polygons service.
@@ -197,7 +199,10 @@ export class MapPolygonsService {
197199

198200
if (geoJSON.features.length > 0) {
199201
// Timeout seems to be needed for first load of the map.
200-
setTimeout(() => {
202+
if (this.fitBoundsTimeoutListener) {
203+
clearTimeout(this.fitBoundsTimeoutListener);
204+
}
205+
this.fitBoundsTimeoutListener = setTimeout(() => {
201206
map.fitBounds(L.geoJSON(geoJSON).getBounds());
202207
}, 500);
203208
}

libs/shared/src/lib/survey/components/resources.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ export const init = (
130130
}
131131
};
132132

133+
/** Display as grid feature timeout listener */
134+
let displayAsGridTimeoutListener!: NodeJS.Timeout;
133135
const component = {
134136
name: 'resources',
135137
title: 'Resources',
@@ -603,8 +605,11 @@ export const init = (
603605
// Display the add button | grid for resources question
604606
const actionsButtons = setUpActionsButtonWrapper();
605607
let gridComponentRef!: ComponentRef<CoreGridComponent>;
608+
if (displayAsGridTimeoutListener) {
609+
clearTimeout(displayAsGridTimeoutListener);
610+
}
606611
// hide tagbox if grid view is enable
607-
setTimeout(() => {
612+
displayAsGridTimeoutListener = setTimeout(() => {
608613
if (question.displayAsGrid) {
609614
const element = el.parentElement?.querySelector('#tagbox');
610615
if (element) {

0 commit comments

Comments
 (0)