Skip to content

Commit 67f5d3f

Browse files
Oleg TeterinNetanelBasal
authored andcommitted
fix(core): lack of unsubscriptions (#65)
1 parent bdd43af commit 67f5d3f

File tree

7 files changed

+68
-29
lines changed

7 files changed

+68
-29
lines changed

projects/ngneat/transloco-persist-lang/src/lib/persist-lang.service.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ import {
66
PersistStorage,
77
TranslocoService
88
} from '@ngneat/transloco';
9+
import { Subscription } from 'rxjs';
910
import { skip } from 'rxjs/operators';
1011
import {
1112
PersistLangConfig,
1213
TRANSLOCO_PERSIST_LANG_CONFIG,
1314
TRANSLOCO_PERSIST_LANG_STORAGE
1415
} from './persist-lang.config';
15-
import { Inject, Injectable } from '@angular/core';
16+
import { Inject, Injectable, OnDestroy } from '@angular/core';
1617

1718
@Injectable({ providedIn: 'root' })
18-
export class TranslocoPersistLangService {
19+
export class TranslocoPersistLangService implements OnDestroy {
20+
private subscription: Subscription = Subscription.EMPTY;
1921
private storageKey: string;
2022

2123
constructor(
@@ -38,16 +40,17 @@ export class TranslocoPersistLangService {
3840
isBrowser() && this.storage.removeItem(this.storageKey);
3941
}
4042

41-
private updateStorageOnLangChange() {
42-
this.service.langChanges$.pipe(skip(1)).subscribe(lang => {
43+
private updateStorageOnLangChange(): Subscription {
44+
return this.service.langChanges$.pipe(skip(1)).subscribe(lang => {
4345
this.save(lang);
4446
});
4547
}
4648

4749
private init() {
4850
// We need to first set the cached lang and then listen to changes
4951
this.setActiveLang();
50-
this.updateStorageOnLangChange();
52+
this.subscription.unsubscribe();
53+
this.subscription = this.updateStorageOnLangChange();
5154
}
5255

5356
private setActiveLang() {
@@ -73,4 +76,9 @@ export class TranslocoPersistLangService {
7376
}
7477
this.storage.setItem(this.storageKey, lang);
7578
}
79+
80+
ngOnDestroy() {
81+
this.subscription.unsubscribe();
82+
}
83+
7684
}

projects/ngneat/transloco-persist-translations/src/lib/transloco-persist-translations.service.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { isObject, isString, Translation, TranslocoLoader } from '@ngneat/transloco';
2-
import { from, Observable, of } from 'rxjs';
2+
import { from, Observable, of, Subscription } from 'rxjs';
33
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
44
import { now, observify } from './helpers';
55
import {
@@ -9,13 +9,14 @@ import {
99
PERSIST_TRANSLATIONS_STORAGE,
1010
TranslocoPersistTranslationsConfig
1111
} from './transloco-persist-translations.config';
12-
import { Inject, Injectable } from '@angular/core';
12+
import { Inject, Injectable, OnDestroy } from '@angular/core';
1313
import { MaybeAsyncStorage } from './transloco.storage';
1414

1515
const getTimestampKey = key => `${key}/timestamp`;
1616

1717
@Injectable()
18-
export class TranslocoPersistTranslations implements TranslocoLoader {
18+
export class TranslocoPersistTranslations implements TranslocoLoader, OnDestroy {
19+
private subscription: Subscription;
1920
private merged: TranslocoPersistTranslationsConfig;
2021
private cache: Translation | null = null;
2122

@@ -25,7 +26,7 @@ export class TranslocoPersistTranslations implements TranslocoLoader {
2526
@Inject(PERSIST_TRANSLATIONS_CONFIG) private config: TranslocoPersistTranslationsConfig
2627
) {
2728
this.merged = { ...defaultConfig, ...(config || {}) };
28-
this.clearCurrentStorage();
29+
this.subscription = this.clearCurrentStorage().subscribe();
2930
}
3031

3132
getTranslation(lang: string): Observable<Translation> {
@@ -101,9 +102,9 @@ export class TranslocoPersistTranslations implements TranslocoLoader {
101102
this.storage.removeItem(this.merged.storageKey);
102103
}
103104

104-
private clearCurrentStorage() {
105+
private clearCurrentStorage(): Observable<any> {
105106
const storageKey = this.merged.storageKey;
106-
this.getTimestamp(storageKey)
107+
return this.getTimestamp(storageKey)
107108
.pipe(
108109
filter(time => !!time),
109110
tap(time => {
@@ -113,6 +114,10 @@ export class TranslocoPersistTranslations implements TranslocoLoader {
113114
}
114115
})
115116
)
116-
.subscribe();
117117
}
118+
119+
ngOnDestroy() {
120+
this.subscription.unsubscribe();
121+
}
122+
118123
}

projects/ngneat/transloco-preload-langs/src/lib/transloco-preload-langs.module.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Inject, ModuleWithProviders, NgModule } from '@angular/core';
1+
import { Inject, ModuleWithProviders, NgModule, OnDestroy } from '@angular/core';
22
import { getPipeValue, TranslocoService } from '@ngneat/transloco';
3-
import { forkJoin } from 'rxjs';
3+
import { forkJoin, Subscription } from 'rxjs';
44
import { tap } from 'rxjs/operators';
55

66
declare global {
@@ -31,7 +31,10 @@ window.cancelIdleCallback =
3131
};
3232

3333
@NgModule()
34-
export class TranslocoPreloadLangsModule {
34+
export class TranslocoPreloadLangsModule implements OnDestroy {
35+
private idleCallbackId: any;
36+
private subscription: Subscription = Subscription.EMPTY;
37+
3538
static preload(langs: string[]): ModuleWithProviders {
3639
return {
3740
ngModule: TranslocoPreloadLangsModule,
@@ -41,7 +44,7 @@ export class TranslocoPreloadLangsModule {
4144

4245
constructor(service: TranslocoService, @Inject('PreloadLangs') langs: string[]) {
4346
if (!langs) return;
44-
window.requestIdleCallback(() => {
47+
this.idleCallbackId = window.requestIdleCallback(() => {
4548
const preloads = langs.map(currentLang => {
4649
const [isScoped, scopedPath] = getPipeValue(currentLang, 'scoped');
4750
const lang = isScoped ? `${scopedPath}/${service.getActiveLang()}` : currentLang;
@@ -53,7 +56,15 @@ export class TranslocoPreloadLangsModule {
5356
})
5457
);
5558
});
56-
forkJoin(preloads).subscribe();
59+
this.subscription = forkJoin(preloads).subscribe();
5760
});
5861
}
62+
63+
ngOnDestroy() {
64+
if (this.idleCallbackId !== undefined) {
65+
window.cancelIdleCallback(this.idleCallbackId);
66+
}
67+
this.subscription.unsubscribe();
68+
}
69+
5970
}

projects/ngneat/transloco/src/lib/transloco.directive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { shouldListenToLangChanges } from './shared';
2828
selector: '[transloco]'
2929
})
3030
export class TranslocoDirective implements OnInit, OnDestroy, OnChanges {
31-
subscription: Subscription;
31+
subscription: Subscription = Subscription.EMPTY;
3232
view: EmbeddedViewRef<any>;
3333

3434
@Input('transloco') key: string;
@@ -147,7 +147,7 @@ export class TranslocoDirective implements OnInit, OnDestroy, OnChanges {
147147
}
148148

149149
ngOnDestroy() {
150-
this.subscription && this.subscription.unsubscribe();
150+
this.subscription.unsubscribe();
151151
}
152152

153153
private detachLoader() {

projects/ngneat/transloco/src/lib/transloco.pipe.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { shouldListenToLangChanges } from './shared';
1313
pure: false
1414
})
1515
export class TranslocoPipe implements PipeTransform, OnDestroy {
16-
subscription: Subscription;
16+
subscription: Subscription = Subscription.EMPTY;
1717
value: string = '';
1818
lastKey: string;
1919
lastParams: HashMap;
@@ -43,7 +43,7 @@ export class TranslocoPipe implements PipeTransform, OnDestroy {
4343
this.lastParams = params;
4444

4545
/* Clean previous subscription if exists */
46-
this.subscription && this.subscription.unsubscribe();
46+
this.subscription.unsubscribe();
4747

4848
this.subscription = this.translocoService.langChanges$
4949
.pipe(
@@ -60,7 +60,7 @@ export class TranslocoPipe implements PipeTransform, OnDestroy {
6060
}
6161

6262
ngOnDestroy() {
63-
this.subscription && this.subscription.unsubscribe();
63+
this.subscription.unsubscribe();
6464
}
6565

6666
private updateValue(key: string, params?: HashMap): void {

projects/ngneat/transloco/src/lib/transloco.service.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Inject, Injectable, Optional } from '@angular/core';
2-
import { BehaviorSubject, combineLatest, from, Observable, Subject, of } from 'rxjs';
1+
import { Inject, Injectable, OnDestroy, Optional } from '@angular/core';
2+
import { BehaviorSubject, combineLatest, from, Observable, Subject, of, Subscription } from 'rxjs';
33
import { catchError, distinctUntilChanged, map, retry, shareReplay, tap, switchMap } from 'rxjs/operators';
44
import { DefaultLoader, TRANSLOCO_LOADER, TranslocoLoader } from './transloco.loader';
55
import { TRANSLOCO_TRANSPILER, TranslocoTranspiler } from './transloco.transpiler';
@@ -28,7 +28,8 @@ export function translate<T = any>(key: TranslateParams, params: HashMap = {}, l
2828
}
2929

3030
@Injectable({ providedIn: 'root' })
31-
export class TranslocoService {
31+
export class TranslocoService implements OnDestroy {
32+
private subscription: Subscription;
3233
private translations = new Map<string, Translation>();
3334
private cache = new Map<string, Observable<Translation>>();
3435
private defaultLang: string;
@@ -64,7 +65,7 @@ export class TranslocoService {
6465
/**
6566
* When we have a failure, we want to define the next language that succeeded as the active
6667
*/
67-
this.events$.subscribe(e => {
68+
this.subscription = this.events$.subscribe(e => {
6869
if (e.type === 'translationLoadSuccess' && e.wasFailure) {
6970
// Handle scoped lang
7071
const lang = getLangFromScope(e.payload.lang);
@@ -351,4 +352,9 @@ export class TranslocoService {
351352

352353
return this.load(resolveLang);
353354
}
355+
356+
ngOnDestroy() {
357+
this.subscription.unsubscribe();
358+
}
359+
354360
}

src/app/app.component.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import { Component } from '@angular/core';
1+
import { Component, OnDestroy } from '@angular/core';
22
import { TranslocoService } from '@ngneat/transloco';
3+
import { Subscription } from 'rxjs';
34
import { take } from 'rxjs/operators';
45

56
@Component({
67
selector: 'app-root',
78
templateUrl: './app.component.html',
89
styleUrls: ['./app.component.css']
910
})
10-
export class AppComponent {
11+
export class AppComponent implements OnDestroy {
12+
private subscription: Subscription = Subscription.EMPTY;
13+
1114
constructor(private service: TranslocoService) {}
1215

1316
get activeLang() {
@@ -16,11 +19,17 @@ export class AppComponent {
1619

1720
change(lang: string) {
1821
// Ensure new active lang is loaded
19-
this.service
22+
this.subscription.unsubscribe();
23+
this.subscription = this.service
2024
.load(lang)
2125
.pipe(take(1))
2226
.subscribe(() => {
2327
this.service.setActiveLang(lang);
2428
});
2529
}
30+
31+
ngOnDestroy() {
32+
this.subscription.unsubscribe();
33+
}
34+
2635
}

0 commit comments

Comments
 (0)