Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/piotrekn/ng-rxjs-safe-subscribe
Implementation of Angular's repeatable OnDestroy pattern
https://github.com/piotrekn/ng-rxjs-safe-subscribe
angular rxjs
Last synced: 23 days ago
JSON representation
Implementation of Angular's repeatable OnDestroy pattern
- Host: GitHub
- URL: https://github.com/piotrekn/ng-rxjs-safe-subscribe
- Owner: piotrekn
- License: isc
- Created: 2021-03-05T22:04:06.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2024-12-22T12:20:56.000Z (about 1 month ago)
- Last Synced: 2024-12-22T12:43:29.244Z (about 1 month ago)
- Topics: angular, rxjs
- Language: TypeScript
- Homepage:
- Size: 586 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
- awesome-angular - ng-rxjs-safe-subscribe - Implementation of Angular's repeatable OnDestroy pattern. (Table of contents / Third Party Components)
README
ng-rxjs-safe-subscribe
Implementation of Angular's repeatable OnDestroy pattern.# Why do I need it?
Because of the DRY principle. Instead of reimplementing the pattern in every component:
```typescript
export class MyComponent implements OnDestroy {
private booksSubscription: Subscription;getBooks(): void {
this.booksSubscription = this.booksService.getBooks().subscribe((books) =>
(...)
);
}ngOnDestroy(): void {
this.booksSubscription.unsubscribe();
}
}
```simplify the code and just subscribe safely:
```typescript
export class MyComponent extends RxjsOnDestroy {
getBooks(): void {
this.booksService.getBooks().subscribeSafely(this, (books) =>
(...)
);
}
}
```One of the most common mistakes made with RxJS is subscribing to an Observable in a fire-and-forget manner.
A rule of thumb is that a subscriber should unsubscribe when no longer using an observable. If there is no explicit unsubscribe, then those books will be pushed to subscribe function infinitely. While it may not be the case for some observable sources, it can silently become an issue and cause a leaks leading to unwanted behaviors.
There are a few ways to deal with unsubscribing. A direct:
1. calling unsubscribe() directly on subscription.
... or more declarative one using RxJs:
2. using operator: takeUntil, takeWhile (declarative unsubscribe),
3. taking a finite number of values: first, take(n) - it'll unsubscribe after n emits, and only then,
4. async pipe in HTML template - takes care of the issue automagically.Package `ng-rxjs-safe-subscribe` provides a ready-to-use solution for every Angular project.
# Installation
Install `ng-rxjs-safe-subscribe` from `npm`:
```bash
npm install ng-rxjs-safe-subscribe
```Import an abstract class:
```typescript
import { RxjsOnDestroy } from 'ng-rxjs-safe-subscribe';
```Extend the class with `RxjsOnDestroy` that implements the `OnDestroy` hook.
```typescript
export class AppComponent extends RxjsOnDestroy
```Finally, use one of the following approaches to subscribe in code using `Observable.subscribeSafely` or `Observable.subscribeUntil` function.
## How to execute custom logic at `ngOnDestroy`
Consider passing an arrow function with custom destroy logic to the constructor:
```typescript
constructor() {
super(() => this.customDestroy());
}
```The `ngOnDestroy` function can be also easily overridden, but be sure to always call the base function for `RxjsOnDestroy` to unsubscribe properly:
```typescript
override ngOnDestroy(){
super.ngOnDestroy();...
}
```Typescript can help you avoid mistaken overrides with [noImplicitOverride](https://www.typescriptlang.org/tsconfig#noImplicitOverride) rule. It is HIGHLY RECOMMENDED to enable that.
## 1. Unsubscribe with a sink
Subscribe safely, pass an object which extends RxjsOnDestroy abstract class:
```typescript
this.users$.subscribeSafely(rxjsOnDestroyInstance, (x) => console.log(x));
```Full example:
```typescript
import { Component } from '@angular/core';
import { RxjsOnDestroy } from 'ng-rxjs-safe-subscribe';
import { Observable } from 'rxjs';@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent extends RxjsOnDestroy {
users$: Observable;constructor(private userService: UserService) {
super();this.users$ = this.userService.getUsers();
this.users$.subscribeSafely(this, (x) => console.log(x));
}
}
```## 2. Declarative unsubscribe
You may pass an observable instance that triggers unsubscribe by passing a value and completion:
```typescript
this.users$.subscribeUntil(this.destroy$, (x) => console.log(x));
```The example uses `this.destroy$` of `RxjsOnDestroy` class.
Full example:
```typescript
import { Component } from '@angular/core';
import { RxjsOnDestroy } from 'ng-rxjs-safe-subscribe';
import { Observable, fromEvent, merge } from 'rxjs';@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent extends RxjsOnDestroy {
users$: Observable;constructor(private userService: UserService) {
super();this.users$ = this.userService.getUsers();
const cancelBtn = this.element.querySelector('.cancel-button');
const cancel$ = fromEvent(cancelBtn, 'click');
const stop$ = merge(cancel$, this.destroy$)// will stop when button clicked or component destroyed
this.users$.subscribeUntil(stop$, (x) => console.log(x));// will stop when component destroyed
this.users$.subscribeUntil(this.destroy$, (x) => console.log(x));
}
}
```You can now use stop to kill the subscription in the moment of your choosing, but remember to always unsubscribe on object destruction.
Read up [Ben Lesh's article](https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87) for more on this topic.
# What about Signals?
Signals can be an answer to this kind of issue. If you just want to provide a value from rxjs Observable, consider using Signals.
# Compatibility
The only two dependencies are [Angular](https://angular.io) and [RxJS](https://rxjs-dev.firebaseapp.com/guide/overview).
Here is the versions compatibility list:| ng-rxjs-safe-subscribe | Angular | RxJS |
| ---------------------- | ------- | ----- |
| 18.x.x | 18.x.x | 7.x.x |
| 17.x.x | 17.x.x | 7.x.x |
| 16.x.x | 16.x.x | 7.x.x |
| 15.x.x | 15.x.x | 7.x.x |
| 14.x.x | 14.x.x | 7.x.x |
| 13.x.x | 13.x.x | 7.x.x |
| 12.x.x | 12.x.x | 6.x.x |
| 11.x.x | 11.x.x | 6.x.x |
| 10.x.x | 10.x.x | 6.x.x |The package should work with every version of Angular, as long as the RxJS version is matching yours.
# License
[ISC](https://opensource.org/licenses/ISC)