Skip to content

Commit

Permalink
fix(decorator): implementation
Browse files Browse the repository at this point in the history
And add unit tests + update docs
  • Loading branch information
Alex Malkevich committed Jan 9, 2019
1 parent 1749f15 commit 423a896
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 9 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { untilDestroyed } from 'ngx-take-until-destroy';

@Component({
selector: 'app-inbox',
templateUrl: './inbox.component.html'
templateUrl: './inbox.component.html',
})
export class InboxComponent implements OnInit, OnDestroy {
ngOnInit() {
Expand All @@ -37,11 +37,11 @@ export class InboxComponent implements OnInit, OnDestroy {
### Use with decorator

```ts
import { AutoUnsubscribe } from 'ngx-take-until-destroy';
import { WithUntilDestroyed } from 'ngx-take-until-destroy';

@Component({...})
class MyComponent implements OnDestroy {
@AutoUnsubscribe()
@WithUntilDestroyed()
stream$ = interval(1000); // You can safely subscribe to this everywhere

// This method must be present, even if empty
Expand Down
62 changes: 62 additions & 0 deletions __tests__/decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { EMPTY, Subject } from 'rxjs';

import * as untilDestroyedObj from '../src/take-until-destroy';

import { WithUntilDestroyed } from '../src/decorator';

describe('@WithUntilDestroyed decorator', () => {
it('should throw when applied on non Observable prop', () => {
class Test {
@WithUntilDestroyed()
notObservable = true;
}

expect(() => new Test()).toThrowError();
});

it('should call `untilDestroyed()` with target prototype and `destroyMethodName` on setter', () => {
const untilDestroyedSpy = spyOn(
untilDestroyedObj,
'untilDestroyed',
).and.callThrough();

class Test {
@WithUntilDestroyed('destroy')
notObservable = EMPTY;

destroy() {}
}

expect(untilDestroyedSpy).not.toHaveBeenCalled();

new Test();

expect(untilDestroyedSpy).toHaveBeenCalledWith(Test.prototype, 'destroy');
});

it('should unsubscribe when `destroyMethodName` was called', () => {
const callback = jest.fn();

class Test {
subject = new Subject<any>();

@WithUntilDestroyed('destroy')
stream$ = this.subject.asObservable();

destroy() {}
}

const test = new Test();
test.stream$.subscribe(callback);

test.subject.next('event');

expect(callback).toHaveBeenCalledWith('event');

callback.mockReset();
test.destroy();
test.subject.next('event');

expect(callback).not.toHaveBeenCalled();
});
});
31 changes: 26 additions & 5 deletions src/decorator.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { isObservable, Observable } from 'rxjs';

import { untilDestroyed } from './take-until-destroy';

/**
* Autamatically unsubscribes from pipe when component destroyed.
* Automatically unsubscribes from pipe when component destroyed.
*
* @example
* ```ts
* @Component({...})
* class MyComponent implements OnDestroy {
* @AutoUnsubscribe()
* @WithUntilDestroyed()
* stream$ = new Observable(...);
*
* // OnDestroy method is required by Angular Compiler
Expand All @@ -19,15 +21,34 @@ import { untilDestroyed } from './take-until-destroy';
*
* Do not forget to implement {@link OnDestroy} life-cycle hook.
*/
export function AutoUnsubscribe(destroyMethodName?: string): PropertyDecorator {
export function WithUntilDestroyed(
destroyMethodName?: string,
): PropertyDecorator {
return (target, propKey) => {
const originalProp = target[propKey];
let val: Observable<any>;

function getter() {
return val;
}

function setter(newVal) {
if (isObservable(newVal)) {
val = newVal.pipe(untilDestroyed(target, destroyMethodName));
} else {
throw Error(
`WithUntilDestroyed: Property ${String(propKey)} on ${
target.constructor.name
} is not Observable!`,
);
}
}

if (delete target[propKey]) {
Object.defineProperty(target, propKey, {
enumerable: true,
configurable: true,
value: (originalProp as Observable<any>).pipe(untilDestroyed(target)),
set: setter,
get: getter,
});
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { untilDestroyed } from './take-until-destroy';
export { AutoUnsubscribe } from './decorator';
export { WithUntilDestroyed as AutoUnsubscribe } from './decorator';

0 comments on commit 423a896

Please sign in to comment.