Skip to content

Commit

Permalink
fix(inject-destroy): add onDestroy to return value of injectDestroy
Browse files Browse the repository at this point in the history
This PR augments the return type of `injectDestroy` to also include `onDestroy` so that folks don't have to `inject(DestroyRef)` when they need it to run arbitrary destroy logic using `DestroyRef#onDestroy`
  • Loading branch information
nartc committed Sep 18, 2023
1 parent 63bf5ad commit 5566741
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 4 deletions.
23 changes: 23 additions & 0 deletions docs/src/content/docs/utilities/inject-destroy.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,29 @@ export class MyComponent {

As you can see, we don't need to implement `OnDestroy` anymore and we don't need to manually emit from the `Subject` when the component is destroyed.

### `onDestroy`

The value returned by `injectDestroy()` also includes `onDestroy()` function to register arbitrary destroy logic callbacks.

```ts

@Component({})
export class MyComponent {
private dataService = inject(DataService);
private destroy$ = injectDestroy();

ngOnInit() {
this.dataService.getData()
.pipe(takeUntil(this.destroy$))
.subscribe(...);

this.destroy$.onDestroy(() => {
/* other destroy logics, similar to DestroyRef#onDestroy */
});
}
}
```

## How it works

The helper functions injects the `DestroyRef` class from Angular, and on the `onDestroy` lifecycle hook, it emits from the `Subject` and completes it.
Expand Down
40 changes: 39 additions & 1 deletion libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { interval, takeUntil } from 'rxjs';
import { injectDestroy } from './inject-destroy';

describe(injectDestroy.name, () => {
describe('emits when the component is destroyed', () => {
describe('emits when the component is destroyed using takeUntil', () => {
@Component({ standalone: true, template: '' })
class TestComponent implements OnInit {
destroy$ = injectDestroy();
Expand Down Expand Up @@ -45,4 +45,42 @@ describe(injectDestroy.name, () => {
expect(component.count).toBe(2);
}));
});

describe('emits when the component is destroyed using onDestroy', () => {
@Component({ standalone: true, template: '' })
class TestComponent implements OnInit {
destroy$ = injectDestroy();
count = 0;

ngOnInit() {
const sub = interval(1000).subscribe(() => this.count++);
this.destroy$.onDestroy(() => {
sub.unsubscribe();
});
}
}

let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;

beforeEach(async () => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
});

it('should handle async stuff', fakeAsync(() => {
component.ngOnInit();

expect(component.count).toBe(0);
tick(1000);
expect(component.count).toBe(1);
tick(1000);
expect(component.count).toBe(2);

fixture.destroy(); // destroy the component here

tick(1000);
expect(component.count).toBe(2);
}));
});
});
14 changes: 11 additions & 3 deletions libs/ngxtension/inject-destroy/src/inject-destroy.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
DestroyRef,
inject,
Injector,
runInInjectionContext,
type Injector,
} from '@angular/core';
import { assertInjector } from 'ngxtension/assert-injector';
import { ReplaySubject } from 'rxjs';
Expand All @@ -26,7 +26,9 @@ import { ReplaySubject } from 'rxjs';
* }
* }
*/
export const injectDestroy = (injector?: Injector) => {
export const injectDestroy = (
injector?: Injector
): ReplaySubject<void> & { onDestroy: DestroyRef['onDestroy'] } => {
injector = assertInjector(injectDestroy, injector);

return runInInjectionContext(injector, () => {
Expand All @@ -39,6 +41,12 @@ export const injectDestroy = (injector?: Injector) => {
subject$.complete();
});

return subject$;
Object.assign(subject$, {
onDestroy: destroyRef.onDestroy.bind(destroyRef),
});

return subject$ as ReplaySubject<void> & {
onDestroy: DestroyRef['onDestroy'];
};
});
};

0 comments on commit 5566741

Please sign in to comment.