From f43695e1cb9ac88896a07d816477b0fd1fe33da6 Mon Sep 17 00:00:00 2001 From: Anvay Date: Fri, 21 Nov 2025 22:53:18 +0530 Subject: [PATCH] WEB-427: Fix memory leak by unsubscribing from form valueChanges in Holiday components - Added OnDestroy lifecycle hook to both Create and Edit Holiday components - Imported Subject and takeUntil from rxjs - Created destroy$ Subject to manage subscription cleanup - Applied takeUntil operator to form valueChanges subscriptions - Properly unsubscribe on component destruction to prevent memory leaks - Fixes potential performance issues from accumulated subscriptions --- .../create-holiday.component.ts | 33 +++++++++++----- .../edit-holiday/edit-holiday.component.ts | 38 ++++++++++++++----- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/app/organization/holidays/create-holiday/create-holiday.component.ts b/src/app/organization/holidays/create-holiday/create-holiday.component.ts index 6926740597..e72f9dafb9 100644 --- a/src/app/organization/holidays/create-holiday/create-holiday.component.ts +++ b/src/app/organization/holidays/create-holiday/create-holiday.component.ts @@ -1,6 +1,6 @@ /** Angular Imports. */ import { SelectionModel } from '@angular/cdk/collections'; -import { Component, OnInit, ViewChild, Injectable } from '@angular/core'; +import { Component, OnInit, OnDestroy, ViewChild, Injectable } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup, @@ -9,6 +9,8 @@ import { ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { Dates } from 'app/core/utils/dates'; import { MatTreeFlatDataSource, @@ -52,7 +54,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; MatIcon ] }) -export class CreateHolidayComponent implements OnInit { +export class CreateHolidayComponent implements OnInit, OnDestroy { /** Create Holiday form. */ holidayForm: UntypedFormGroup; /** Repayment Scheduling data. */ @@ -63,6 +65,8 @@ export class CreateHolidayComponent implements OnInit { minDate = new Date(2000, 0, 1); /** Maximum Date allowed. */ maxDate = new Date(2100, 0, 1); + /** Subject for managing subscriptions. */ + private destroy$ = new Subject(); // Stores office data in a trie-like structure officesTrie: any; // Stores office data for access from DOM via Office ID @@ -314,13 +318,16 @@ export class CreateHolidayComponent implements OnInit { * Sets the conditional controls. */ buildDependencies() { - this.holidayForm.get('reschedulingType').valueChanges.subscribe((option: any) => { - if (option === 2) { - this.holidayForm.addControl('repaymentsRescheduledTo', new UntypedFormControl('', Validators.required)); - } else { - this.holidayForm.removeControl('repaymentsRescheduledTo'); - } - }); + this.holidayForm + .get('reschedulingType') + .valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((option: any) => { + if (option === 2) { + this.holidayForm.addControl('repaymentsRescheduledTo', new UntypedFormControl('', Validators.required)); + } else { + this.holidayForm.removeControl('repaymentsRescheduledTo'); + } + }); } /** @@ -360,4 +367,12 @@ export class CreateHolidayComponent implements OnInit { ); }); } + + /** + * Component lifecycle hook to clean up subscriptions. + */ + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } } diff --git a/src/app/organization/holidays/edit-holiday/edit-holiday.component.ts b/src/app/organization/holidays/edit-holiday/edit-holiday.component.ts index 9bb4f1cc7c..76eaa6a6d8 100644 --- a/src/app/organization/holidays/edit-holiday/edit-holiday.component.ts +++ b/src/app/organization/holidays/edit-holiday/edit-holiday.component.ts @@ -1,5 +1,5 @@ /** Angular Imports. */ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, OnDestroy } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup, @@ -8,6 +8,8 @@ import { ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { Dates } from 'app/core/utils/dates'; /** Custom Services. */ @@ -26,7 +28,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; ...STANDALONE_SHARED_IMPORTS ] }) -export class EditHolidayComponent implements OnInit { +export class EditHolidayComponent implements OnInit, OnDestroy { /** Edit Holiday form. */ holidayForm: UntypedFormGroup; /** Holiday data. */ @@ -39,6 +41,8 @@ export class EditHolidayComponent implements OnInit { minDate = new Date(2000, 0, 1); /** Maximum Date allowed. */ maxDate = new Date(); + /** Subject for managing subscriptions. */ + private destroy$ = new Subject(); /** * Get holiday and holiday template from `Resolver`. @@ -116,14 +120,20 @@ export class EditHolidayComponent implements OnInit { * Get Rescheduling Type. */ getReschedulingType() { - this.holidayForm.get('reschedulingType').valueChanges.subscribe((option: any) => { - this.reSchedulingType = option; - if (option === 2) { - this.holidayForm.addControl('repaymentsRescheduledTo', new UntypedFormControl(new Date(), Validators.required)); - } else { - this.holidayForm.removeControl('repaymentsRescheduledTo'); - } - }); + this.holidayForm + .get('reschedulingType') + .valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((option: any) => { + this.reSchedulingType = option; + if (option === 2) { + this.holidayForm.addControl( + 'repaymentsRescheduledTo', + new UntypedFormControl(new Date(), Validators.required) + ); + } else { + this.holidayForm.removeControl('repaymentsRescheduledTo'); + } + }); } /** @@ -160,4 +170,12 @@ export class EditHolidayComponent implements OnInit { this.router.navigate(['../'], { relativeTo: this.route }); }); } + + /** + * Component lifecycle hook to clean up subscriptions. + */ + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } }