How to avoid multiple subscription in Angular 2 component

2muchcoffee
3 min readNov 26, 2016

--

Preview448 words

I think every Angular 2 developer has faced the situation when there are too many subscriptions in the component. If you unsubscribe manually — you waist too much time and litter the code. If you forgot to do that — your application uses too many resources.

To simulate this situation let’s create the simple router, component and service:

@Injectable()
export class MyService {
name$ = new Subject();
}

Here we create 2 routes: test and home

export const ROUTES: Routes = [  
{ path: '', component: HomeComponent },
{ path: 'test', component: TestComponent }
];

and here we create the component

@Component({
...
})
export class TestComponent {
public subscribers: any = {};
constructor(public myService: AppState){
}
ngAfterViewInit() {
// The subscribe is made each time the view is uploaded
this.subscribers.name = this.myService.name$
.subscribe(name => {
console.log(name)
});
this.myService.name$.next('New Name Created');
}
}

In the added code we make the subscribe and type-out the name to console each time we reach subscribe.

If we will get across the route test several times we'll see that in console the name is typed-out many times. This is really not what we need (subscribe to Observable many times).

Let’s change our component to solve the problem:

// The modified component
@Component({
...
})
export class TestComponent {
public subscribers: any = {};
constructor(public myService: AppState){
}
ngAfterViewInit() {
this.subscribers.name = this.myService.name$
.subscribe(name => {
console.log(name)
});
this.myService.name$.next('New Name Created');
}
// Cleanup just before Angular destroys the directive/component.
// Unsubscribe observables and detach event handlers to avoid memory leaks.
ngOnDestroy(){
this.subscribers.name.unsubscribe();
}
}

After these changes, we’ll get what we expected in console — every time when getting to url ‘/test’ the name will be typed-out once.

But what will happen if we have 20 subscribes in the component? It’s really annoying — to unsubscribe from each Observables in every component.
To forget about unsubscribing — we can make a decorator. The main thing here is to save subscription in the variable this.subscribers, while the other job will be performed by decorator.

Let’s get it started:

// creating the decorator DestroySubscribers
export function DestroySubscribers() {
return function (target: any) {
// decorating the function ngOnDestroy
target.prototype.ngOnDestroy = ngOnDestroyDecorator(target.prototype.ngOnDestroy);
// decorator function
function ngOnDestroyDecorator(f) {
return function () {
// saving the result of ngOnDestroy performance to the variable superData
let superData = f ? f.apply(this, arguments) : null;
// unsubscribing
for (let subscriberKey in this.subscribers) {
let subscriber = this.subscribers[subscriberKey];
if (subscriber instanceof Subscriber) {
subscriber.unsubscribe();
}
}
// returning the result of ngOnDestroy performance
return superData;
}
}
// returning the decorated class
return target;
}
}

Now we can remove the ngOnDestroy from the component and include the decorator that will be doing the same thing.

@Component({
...
})
//here we apply the decorator
@DestroySubscribers()
export class TestComponent {
public subscribers: any = {};
constructor(public myService: AppState){
}
ngAfterViewInit() {
this.subscribers.name = this.myService.name$
.subscribe(name => {
console.log(name)
});
this.myService.name$.next('New Name Created');
}
}

The extended version of the decorator is available here: https://www.npmjs.com/package/ng2-destroy-subscribers

If your Angular2 application has many subscribers or you’re tired of wasting time to make a lot of same code — you can use this decorator.

You can find article here: http://blog.2muchcoffee.com/how-to-avoid-multiple-subscription-in-angular-2-component/

--

--

2muchcoffee

Web and Mobile App Development Company. Live and Breathe Angular and Rx.js. Open source contributors as the guarantee of product delivery. Enjoy your coffee ;)