Skip to content

Instantly share code, notes, and snippets.

@AzrizHaziq
Last active May 2, 2021
Embed
What would you like to do?
...
public ngOnDestroy() {
... // things that you need to clean up
super.ngOnDestroy(); // don't forget to call this line.
}
// Decorators
import { Observable, Subject } from "rxjs";
import { takeUntil, take } from "rxjs/operators";
export function UnsubscribeDecorator(ComponentClass) {
let destroyed$ = new Subject();
const unsubsribeOnDestroy = <T = unknown>(
source: Observable<T>
): Observable<T> => {
destroyed$ = new Subject();
return source.pipe(takeUntil(destroyed$));
};
const once = <T = unknown>(source: Observable<T>): Observable<T> => {
return source.pipe(take(1));
};
const ngOnDestroy = (): void => {
destroyed$.next(true);
destroyed$.complete();
};
Object.assign(ComponentClass.prototype, {
destroyed$,
unsubsribeOnDestroy,
once,
// if target class already have ngOnDestroy implemented, then that class must explicitly call this.killSub$()
...(!!ComponentClass.prototype.ngOnDestroy
? { killSub$: ngOnDestroy }
: { ngOnDestroy })
});
return ComponentClass;
}
// base-inheritence.ts
import { OnDestroy } from "@angular/core";
import { takeUntil, take } from "rxjs/operators";
import { interval, Observable, Subject } from "rxjs";
export class BaseComponent implements OnDestroy {
private isAlive$ = new Subject<any>();
protected unsubsribeOnDestroy = <T = unknown>(source: Observable<T>): Observable<T> =>
source.pipe(takeUntil(this.isAlive$));
// automatic close the subscribtion.
protected once = <T = unknown>(source: Observable<T>): Observable<T> =>
source.pipe(take(1));
/**
* Auto-unsubscribe all subscriptions
* if a component that extend this class, then it should call super.ngOnDestroy()
*/
public ngOnDestroy() {
this.isAlive$.next();
this.isAlive$.complete();
}
}
import { interval, merge } from "rxjs";
import { Component, OnInit, OnDestroy } from "@angular/core";
// Decorator Component
@UnsubscribeDecorator
@Component({
selector: "decorator",
template: "Decorator: see in logs"
})
export class DecoratorComponent implements OnInit, OnDestroy {
ngOnInit() {
interval(1000)
.pipe(
this.unsubsribeOnDestroy, // <--- typescript error need to use // @ts-ignore
tap(e => console.log("D:unsubsribeOnDestroy", e))
)
.subscribe();
merge(
interval(3000).pipe(
tap(e => console.log("D:once", e)),
this.once // <--- typescript error need to use, // @ts-ignore
),
interval(5000).pipe(
tap(e => console.log("D:once:2", e)),
this.once // <--- typescript error need to use // @ts-ignore
)
).subscribe();
}
// implement like this if a component have ngOnDestroy()
ngOnDestroy() {
this.killSub$(); // <---typescript error need to use // @ts-ignore
}
}
import { interval, merge } from "rxjs";
import { Component, OnInit, OnDestroy } from "@angular/core";
// inheritence.component.ts
@Component({
selector: "inheritance",
template: "Inheritance: see in logs"
})
export class InheritanceComponent extends BaseComponent implements OnInit, OnDestroy {
// if you have constructor don't forget to call super().
constructor() {
super();
}
ngOnInit() {
interval(1000)
.pipe(
this.unsubsribeOnDestroy,
tap(e => console.log("I:unsubsribeOnDestroy", e))
)
.subscribe();
interval(3000)
.pipe(
tap(e => console.log("I:once", e)),
this.once
)
.subscribe();
}
// implement like this if a component have ngOnDestroy()
ngOnDestroy() {
super.ngOnDestroy();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment