Skip to content

Commit

Permalink
fix(core): unsubscribe every possible events (#611)
Browse files Browse the repository at this point in the history
* fix(core): unsubscribe every possible events #610
- causes memory heap size to keep growing

* refactor: use subscriptions array instead of single subscription

* fix: remove keydown binding when disposing of externalCopy plugin

* fix: possible leak, body onClick event not unbound in multiple-select
  • Loading branch information
ghiscoding committed Oct 29, 2020
1 parent 32cd122 commit 2a92e78
Show file tree
Hide file tree
Showing 19 changed files with 247 additions and 101 deletions.
13 changes: 8 additions & 5 deletions src/app/examples/custom-angularComponentEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import {
EditorValidator,
EditorValidatorOutput,
GridOption,
unsubscribeAllObservables,
} from './../modules/angular-slickgrid';

/*
* An example of a 'detached' editor.
* KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
*/
export class CustomAngularComponentEditor implements Editor {
changeSubscriber: Subscription;
private _subscriptions: Subscription[] = [];

/** Angular Component Reference */
componentRef: ComponentRef<any>;
Expand Down Expand Up @@ -88,9 +89,9 @@ export class CustomAngularComponentEditor implements Editor {
Object.assign(this.componentRef.instance, { collection: this.collection });

// when our model (item object) changes, we'll call a save of the slickgrid editor
this.changeSubscriber = this.componentRef.instance.onItemChanged.subscribe((item) => {
this.save();
});
this._subscriptions.push(
this.componentRef.instance.onItemChanged.subscribe((item: any) => this.save())
);
}
}

Expand Down Expand Up @@ -131,8 +132,10 @@ export class CustomAngularComponentEditor implements Editor {
destroy() {
if (this.componentRef && this.componentRef.destroy) {
this.componentRef.destroy();
this.changeSubscriber.unsubscribe();
}

// also unsubscribe all Angular Subscriptions
this._subscriptions = unsubscribeAllObservables(this._subscriptions);
}

/** optional, implement a focus method on your Angular Component */
Expand Down
19 changes: 12 additions & 7 deletions src/app/examples/custom-angularComponentFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import {
OperatorType,
OperatorString,
SearchTerm,
unsubscribeAllObservables,
} from './../modules/angular-slickgrid';

// using external non-typed js libraries
declare const $: any;

export class CustomAngularComponentFilter implements Filter {
private _shouldTriggerQuery = true;
changeSubscriber: Subscription;
private _subscriptions: Subscription[] = [];

/** Angular Component Reference */
componentRef: ComponentRef<any>;
Expand Down Expand Up @@ -84,11 +85,13 @@ export class CustomAngularComponentFilter implements Filter {
// but technically you can pass any values you wish to your Component
Object.assign(componentOuput.componentRef.instance, { collection: this.collection });

this.changeSubscriber = componentOuput.componentRef.instance.onItemChanged.subscribe((item) => {
this.callback(undefined, { columnDef: this.columnDef, operator: this.operator, searchTerms: [item.id], shouldTriggerQuery: this._shouldTriggerQuery });
// reset flag for next use
this._shouldTriggerQuery = true;
});
this._subscriptions.push(
componentOuput.componentRef.instance.onItemChanged.subscribe((item) => {
this.callback(undefined, { columnDef: this.columnDef, operator: this.operator, searchTerms: [item.id], shouldTriggerQuery: this._shouldTriggerQuery });
// reset flag for next use
this._shouldTriggerQuery = true;
})
);
});
}
}
Expand All @@ -107,8 +110,10 @@ export class CustomAngularComponentFilter implements Filter {
destroy() {
if (this.componentRef && this.componentRef.destroy) {
this.componentRef.destroy();
this.changeSubscriber.unsubscribe();
}

// also unsubscribe all Angular Subscriptions
this._subscriptions = unsubscribeAllObservables(this._subscriptions);
}

/** Set value(s) on the DOM element */
Expand Down
8 changes: 6 additions & 2 deletions src/app/examples/grid-clientside.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { TranslateService } from '@ngx-translate/core';
import { CustomInputFilter } from './custom-inputFilter';
Expand All @@ -25,7 +25,7 @@ const URL_SAMPLE_COLLECTION_DATA = 'assets/data/collection_500_numbers.json';
@Component({
templateUrl: './grid-clientside.component.html'
})
export class GridClientSideComponent implements OnInit {
export class GridClientSideComponent implements OnInit, OnDestroy {
title = 'Example 4: Client Side Sort/Filter';
subTitle = `
Sort/Filter on client side only using SlickGrid DataView (<a href="https://github.com/ghiscoding/Angular-Slickgrid/wiki/Sorting" target="_blank">Wiki docs</a>)
Expand Down Expand Up @@ -280,4 +280,8 @@ export class GridClientSideComponent implements OnInit {
});
}
}

ngOnDestroy() {
this.angularGrid.destroy();
}
}
21 changes: 16 additions & 5 deletions src/app/examples/grid-contextmenu.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs';
import {
AngularGridInstance,
Column,
Expand All @@ -10,6 +11,7 @@ import {
Formatter,
Formatters,
GridOption,
unsubscribeAllObservables,
} from './../modules/angular-slickgrid';

const actionFormatter: Formatter = (row, cell, value, columnDef, dataContext) => {
Expand Down Expand Up @@ -58,7 +60,7 @@ const taskTranslateFormatter: Formatter = (row: number, cell: number, value: any
styleUrls: ['./grid-contextmenu.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class GridContextMenuComponent implements OnInit {
export class GridContextMenuComponent implements OnInit, OnDestroy {
title = 'Example 26: Cell Menu & Context Menu Plugins';
subTitle = `Add Cell Menu and Context Menu
<ul>
Expand Down Expand Up @@ -86,6 +88,7 @@ export class GridContextMenuComponent implements OnInit {
</ol>
</ul>`;

private subscriptions: Subscription[] = [];
angularGrid: AngularGridInstance;
columnDefinitions: Column[];
gridOptions: GridOption;
Expand Down Expand Up @@ -116,6 +119,11 @@ export class GridContextMenuComponent implements OnInit {
this.dataset = this.getData(1000);
}

ngOnDestroy() {
// also unsubscribe all Angular Subscriptions
this.subscriptions = unsubscribeAllObservables(this.subscriptions);
}

prepareGrid() {
this.columnDefinitions = [
{ id: 'id', name: '#', field: 'id', maxWidth: 45, sortable: true, filterable: true },
Expand Down Expand Up @@ -453,8 +461,11 @@ export class GridContextMenuComponent implements OnInit {

switchLanguage() {
const nextLanguage = (this.selectedLanguage === 'en') ? 'fr' : 'en';
this.translate.use(nextLanguage).subscribe(() => {
this.selectedLanguage = nextLanguage;
});

this.subscriptions.push(
this.translate.use(nextLanguage).subscribe(() => {
this.selectedLanguage = nextLanguage;
})
);
}
}
10 changes: 8 additions & 2 deletions src/app/examples/grid-frozen.component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core';
import { AngularGridInstance, Column, ColumnEditorDualInput, Editors, FieldType, formatNumber, Formatters, Filters, GridOption } from './../modules/angular-slickgrid';

@Component({
templateUrl: './grid-frozen.component.html',
styleUrls: ['./grid-frozen.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class GridFrozenComponent implements OnInit {
export class GridFrozenComponent implements OnInit, OnDestroy {
title = 'Example 20: Pinned (frozen) Columns/Rows';
subTitle = `
This example demonstrates the use of Pinned (aka frozen) Columns and/or Rows (<a href="https://github.com/ghiscoding/Angular-Slickgrid/wiki/Pinned-(aka-Frozen)-Columns-Rows" target="_blank">Wiki docs</a>)
Expand All @@ -31,6 +31,12 @@ export class GridFrozenComponent implements OnInit {
this.prepareDataGrid();
}

ngOnDestroy() {
// unsubscribe every SlickGrid subscribed event (or use the Slick.EventHandler)
this.gridObj.onMouseEnter.unsubscribe();
this.gridObj.onMouseLeave.unsubscribe();
}

angularGridReady(angularGrid: AngularGridInstance) {
this.angularGrid = angularGrid;
this.gridObj = angularGrid.slickGrid;
Expand Down
18 changes: 12 additions & 6 deletions src/app/examples/grid-graphql.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
MultipleSelectOption,
OperatorType,
SortDirection,
unsubscribeAllObservables,
} from './../modules/angular-slickgrid';
import * as moment from 'moment-mini';
import { Subscription } from 'rxjs';
Expand Down Expand Up @@ -43,6 +44,7 @@ export class GridGraphqlComponent implements OnInit, OnDestroy {
<li>You can also preload a grid with certain "presets" like Filters / Sorters / Pagination <a href="https://github.com/ghiscoding/Angular-Slickgrid/wiki/Grid-State-&-Preset" target="_blank">Wiki - Grid Preset</a>
</ul>
`;
private subscriptions: Subscription[] = [];
angularGrid: AngularGridInstance;
columnDefinitions: Column[];
gridOptions: GridOption;
Expand All @@ -54,7 +56,6 @@ export class GridGraphqlComponent implements OnInit, OnDestroy {
status = { text: 'processing...', class: 'alert alert-danger' };
isWithCursor = false;
selectedLanguage: string;
gridStateSub: Subscription;

constructor(private translate: TranslateService) {
// always start with English for Cypress E2E tests to be consistent
Expand All @@ -64,7 +65,8 @@ export class GridGraphqlComponent implements OnInit, OnDestroy {
}

ngOnDestroy() {
this.gridStateSub.unsubscribe();
// also unsubscribe all Angular Subscriptions
this.subscriptions = unsubscribeAllObservables(this.subscriptions);
}

ngOnInit(): void {
Expand Down Expand Up @@ -208,7 +210,9 @@ export class GridGraphqlComponent implements OnInit, OnDestroy {

angularGridReady(angularGrid: AngularGridInstance) {
this.angularGrid = angularGrid;
this.gridStateSub = this.angularGrid.gridStateService.onGridStateChanged.subscribe((data) => console.log(data));
this.subscriptions.push(
this.angularGrid.gridStateService.onGridStateChanged.subscribe((data) => console.log(data))
);
}

displaySpinner(isProcessing) {
Expand Down Expand Up @@ -294,8 +298,10 @@ export class GridGraphqlComponent implements OnInit, OnDestroy {

switchLanguage() {
const nextLanguage = (this.selectedLanguage === 'en') ? 'fr' : 'en';
this.translate.use(nextLanguage).subscribe(() => {
this.selectedLanguage = nextLanguage;
});
this.subscriptions.push(
this.translate.use(nextLanguage).subscribe(() => {
this.selectedLanguage = nextLanguage;
})
);
}
}
21 changes: 15 additions & 6 deletions src/app/examples/grid-headermenu.component.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { AngularGridInstance, Column, GridOption } from './../modules/angular-slickgrid';
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { AngularGridInstance, Column, GridOption, unsubscribeAllObservables } from './../modules/angular-slickgrid';
import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs';

@Component({
templateUrl: './grid-headermenu.component.html',
styleUrls: ['./grid-headermenu.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class GridHeaderMenuComponent implements OnInit {
export class GridHeaderMenuComponent implements OnInit, OnDestroy {
title = 'Example 8: Header Menu Plugin';
subTitle = `
This example demonstrates using the <b>Slick.Plugins.HeaderMenu</b> plugin to easily add menus to colum headers.<br/>
Expand All @@ -29,6 +30,7 @@ export class GridHeaderMenuComponent implements OnInit {
</ul>
`;

private subscriptions: Subscription[] = [];
angularGrid: AngularGridInstance;
columnDefinitions: Column[];
gridOptions: GridOption;
Expand All @@ -39,6 +41,11 @@ export class GridHeaderMenuComponent implements OnInit {
this.selectedLanguage = this.translate.getDefaultLang();
}

ngOnDestroy() {
// also unsubscribe all Angular Subscriptions
this.subscriptions = unsubscribeAllObservables(this.subscriptions);
}

ngOnInit(): void {
this.columnDefinitions = [
{ id: 'title', name: 'Title', field: 'title', nameKey: 'TITLE' },
Expand Down Expand Up @@ -143,8 +150,10 @@ export class GridHeaderMenuComponent implements OnInit {

switchLanguage() {
const nextLanguage = (this.selectedLanguage === 'en') ? 'fr' : 'en';
this.translate.use(nextLanguage).subscribe(() => {
this.selectedLanguage = nextLanguage;
});
this.subscriptions.push(
this.translate.use(nextLanguage).subscribe(() => {
this.selectedLanguage = nextLanguage;
})
);
}
}
22 changes: 16 additions & 6 deletions src/app/examples/grid-localization.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component, OnInit, Injectable } from '@angular/core';
import { Component, OnDestroy, OnInit, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs';
import {
AngularGridInstance,
Column,
Expand All @@ -10,7 +11,8 @@ import {
Formatter,
Formatters,
GridOption,
GridStateChange
GridStateChange,
unsubscribeAllObservables
} from './../modules/angular-slickgrid';

const NB_ITEMS = 1500;
Expand All @@ -27,7 +29,7 @@ const taskTranslateFormatter: Formatter = (row: number, cell: number, value: any
templateUrl: './grid-localization.component.html'
})
@Injectable()
export class GridLocalizationComponent implements OnInit {
export class GridLocalizationComponent implements OnInit, OnDestroy {
title = 'Example 12: Localization (i18n)';
subTitle = `Support multiple locales with the ngx-translate plugin, following these steps (<a href="https://github.com/ghiscoding/Angular-Slickgrid/wiki/Localization" target="_blank">Wiki docs</a>)
<ol class="small">
Expand Down Expand Up @@ -55,6 +57,7 @@ export class GridLocalizationComponent implements OnInit {
</ol>
`;

private subscriptions: Subscription[] = [];
angularGrid: AngularGridInstance;
columnDefinitions: Column[];
gridOptions: GridOption;
Expand All @@ -70,6 +73,11 @@ export class GridLocalizationComponent implements OnInit {
this.selectedLanguage = defaultLang;
}

ngOnDestroy() {
// also unsubscribe all Angular Subscriptions
this.subscriptions = unsubscribeAllObservables(this.subscriptions);
}

ngOnInit(): void {
this.columnDefinitions = [
{
Expand Down Expand Up @@ -266,8 +274,10 @@ export class GridLocalizationComponent implements OnInit {

switchLanguage() {
const nextLanguage = (this.selectedLanguage === 'en') ? 'fr' : 'en';
this.translate.use(nextLanguage).subscribe(() => {
this.selectedLanguage = nextLanguage;
});
this.subscriptions.push(
this.translate.use(nextLanguage).subscribe(() => {
this.selectedLanguage = nextLanguage;
})
);
}
}

0 comments on commit 2a92e78

Please sign in to comment.