'angular, quirky memory leak
Using Angular ~11. I've got memory leak that keeps the component in memory. I've hollowed out the html and the component.ts. I can get the component to release if I don't have anything inside a particular div, but soon as I put simple text in (no binding, just text) i get a memory leak. the component sticks in memory.
here is html. Note everything is commented out. I have the hello world div, that works if i comment out the Uh-Oh memory tag.
uh-memory leak text in, memory leak. uh-memory leak text commented out, not memory leak.
What is going on here?
<h1 style="background-color:aquamarine" (click)="clickMain($event)">Hello World</h1>
<div>
<h1>I'm a potato</h1>
</div>
<div class="pour-page no-selection" (click)="clickMain($event)">
<!-- <div class="water-selector no-selection" [class.hide]="isPouringStarted" (click)="onSelectorClicked($event)">
<v-water-selector vid="pour_water_selector"></v-water-selector>
</div> -->
<h2>Uh-Oh, memory leak</h2>
<!-- drink configuration -->
<!-- <mat-card class="details-card no-selection" [class.hide]="isPouringStarted" (click)="onCardClicked($event)">
<div class="top-container no-selection">
<div class="thumbnail-container no-selection">
<img class="thumbnail no-selection" [src]="logo" />
</div>
<div class="flavor-name-container no-selection" [style.color]="textColor">
<p class="flavor-name no-selection" [class.water]="isWater">{{ flavorName }}</p>
</div>
<p class="calories-container no-selection">10 CAL PER 40 FL OZ</p>
<app-flavor-intensity *ngIf="isNotWater"></app-flavor-intensity>
<app-sparkling-intensity *ngIf="isSparkling"></app-sparkling-intensity>
<app-water-temperature [isSparkling]="isSparkling"></app-water-temperature>
</div>
<div class="divider"></div>
<app-auto-fill></app-auto-fill>
</mat-card> -->
<!-- <div [ngClass]="isPouringStarted ? 'pour-logo' : 'non-pour-logo'">
<div class="thumbnail-container">
<img
class="thumbnail no-selection"
[src]="logo"
[@resizeAnimation]="{
value: isPouringStarted ? 'grow' : 'shrink',
params: { maxHeight: '605px', minHeight: '300px', growTime: '0.5s', shrinkTime: '0.5s' }
}"
/>
</div>
</div> -->
<!-- <div class="footer-container no-selection" (click)="onFooterClicked($event)">
<div class="pour-btn-container no-selection">
<v-pour-button [isPouring]="isPouring" vid="pour_btn" style="user-select: none !important"></v-pour-button>
</div>
</div> -->
<!-- <div class="done-btn-container" *ngIf="isAutoPour && !isPouring">
<v-button vid="done_btn"></v-button>
</div> -->
<!-- <div class="absolute-container download-container" *ngIf="isPouringStarted">
<div class="pouring-circle">
<div class="phone-img">
<app-phone-circle-svg [color1]="gradientColor1" [color2]="gradientColor2"></app-phone-circle-svg>
</div>
<div class="title">
<v-text-block vid="download_app"></v-text-block>
</div>
<div class="hydration-container">
<v-text-block vid="track_hydration"></v-text-block>
</div>
</div>
</div> -->
<!-- <div class="absolute-container bottle-saved-container" *ngIf="isPouringStarted">
<div class="pouring-circle no-selection" [style.color]="textColor">
<div class="bottle-img">
<app-bottle-svg [color1]="gradientColor1" [color2]="gradientColor2"></app-bottle-svg>
</div>
{{ bottlesSaved }}
<div class="title">
<v-text-block vid="bottle_saved"></v-text-block>
</div>
<div class="hydration-container">
{{ bottleSavedText }}
</div>
</div>
</div> -->
</div>
now, the component typescript, again, most of it is commented out, what's left is what t needs to navigate away. Not the clickMain, works fine if uh-oh is commented out.
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ConfigurationData, LineAssignment, PubSubTopic } from 'src/app/universal/app.types';
import { NavigationStart, Router } from '@angular/router';
import { AppInfoService } from 'src/app/services/app-info.service';
import { JsUtil } from 'src/app/pubsub/JsUtil';
import { LocalizationService } from 'src/app/services/localization.service';
import { PourService } from 'src/app/services/pour.service';
import { SelectionController } from 'src/app/services/selection-controller';
import { SubscribeEvent } from 'src/app/pubsub/pubsub.builder';
import { Subscription } from 'rxjs';
import { resizeAnimation } from 'src/app/ui/animations/animations';
import { SettingsManager } from 'src/app/services/settings-manager.service';
@Component({
selector: 'app-pour-page',
templateUrl: './pour-page.component.html',
styleUrls: ['./pour-page.component.scss'],
animations: [resizeAnimation]
})
export class PourPageComponent implements OnInit, OnDestroy {
objectId = JsUtil.getObjectId();
ignoreMainClick = true;
isPouringStarted = false;
_wasPouring: boolean = false;
timeoutTimer: NodeJS.Timer;
ignoreInitialClickTimer: NodeJS.Timer;
timeoutDelay = 5;
private routeSub: Subscription;
constructor(
private appInfo: AppInfoService,
private pourService: PourService,
private router: Router,
private selectionController: SelectionController,
private localizationService: LocalizationService
) {
console.log('ctor.PourPageComponent');
// if (!this.appInfo.selectedFlavor) {
// this.appInfo.navigateToPage('v1/selector');
// }
// this.routeSub = this.router.events.subscribe((event) => {
// if (event instanceof NavigationStart) {
// // this.pourService.stopPour();
// // this.selectionController.resetDefault();
// // this.pourService.resetAutoPour();
// }
// });
// SubscribeEvent.Create(PubSubTopic.configurationDataReady, this.objectId)
// .HandleEventWithThisMethod((e) => this.onDataReady(e.data))
// .Done();
}
// private onDataReady(e: ConfigurationData) {
// this.timeoutDelay = SettingsManager.getAsNumber('pourpage.timeout.delay');
// }
// get selectedFlavor(): LineAssignment {
// return this.appInfo.selectedFlavor;
// }
// get isSparkling(): boolean {
// return this.appInfo.selectedWater === 'sparkling';
// }
// get gradientColor1(): string {
// return this.selectedFlavor.bibItem.design.gradientColor1;
// }
// get isAutoPour(): boolean {
// return this.pourService.isAutoPour;
// }
// get gradientColor2(): string {
// return this.selectedFlavor.bibItem.design.gradientColor2;
// }
// get isPouring(): boolean {
// this.setIsPouringStarted();
// return this.pourService.isPouring;
// }
// private setIsPouringStarted() {
// if (this.pourService.isPouring) {
// this.isPouringStarted = true;
// }
// if (this.pourService.isPouring !== this._wasPouring && this.timeoutTimer) {
// clearTimeout(this.timeoutTimer);
// }
// if (!this.pourService.isPouring && this._wasPouring) {
// this.timeoutTimer = setTimeout(() => {
// this.appInfo.navigateToPage('v1/selector');
// }, this.timeoutDelay * 1000);
// }
// this._wasPouring = this.pourService.isPouring;
// }
// get isNotWater(): boolean {
// // return this.selectedFlavor.bibItem.Id !== 'carb-water' && this.appInfo.selectedFlavor.bibItem.Id !== 'still-water';
// //return this.selectedFlavor.bibItem.Type !== 'water';
// }
// get bottlesSaved(): number {
// return this.appInfo.bottlesSaved;
// }
// get bottleSavedText(): string {
// return `${this.bottlesSaved} 16-oz ${this.localizationService.localizeString('plastic_bottles_id')}`;
// }
// get logo(): string {
// if (this.appInfo.selectedWater === 'still') {
// return this.selectedFlavor.bibItem.design.stillImageUrl;
// }
// return this.selectedFlavor.bibItem.design.sparklingImageUrl;
// }
// get flavorName(): string {
// return this.selectedFlavor.bibItem.design.title;
// }
// get textColor(): string {
// return this.selectedFlavor.bibItem.design.textColor;
// }
// get isWater(): boolean {
// return this.selectedFlavor.bibItemSKU === 'plain' || this.selectedFlavor.bibItemSKU === 'carb';
// }
ngOnInit(): void {
this.ignoreInitialClickTimer = setTimeout(() => {
this.ignoreMainClick = false;
}, 100);
}
ngOnDestroy(): void {
//this.routeSub.unsubscribe();
SubscribeEvent.UnSubscribeByConsumer(this.objectId);
if (this.timeoutTimer) {
clearTimeout(this.timeoutTimer);
}
clearTimeout(this.ignoreInitialClickTimer);
}
clickMain(event: MouseEvent) {
event.stopPropagation();
if (this.ignoreMainClick === false) {
this.appInfo.navigateToPage('v1/selector');
}
}
// onSelectorClicked(event: MouseEvent) {
// event.stopPropagation();
// }
// onCardClicked(event: MouseEvent) {
// event.stopPropagation();
// }
// onFooterClicked(event: MouseEvent) {
// event.stopPropagation();
// }
// get flavorColor(): string {
// return this.appInfo.selectedFlavor.bibItem.design.color;
// }
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|