fbpx Skip to content

Aquent | DEV6

Angular 2: Cleaning up Observables

Written by: Alain Thibodeau

Observables in Angular 2 help us work with asynchronous data that may be coming from various sources such as UI event or sockets. When using Observables we must be careful to properly clean up what we create. In most cases Angular and Observables clean up themselves, but we should be aware of what is happening.

Lets starts with a simple Observable. I will only show the relevant parts, to see a working version check out the Plunker.

@Component({

  selector: 'my-app',

  template: '<h2>Mouse Position: {{position}}</h2>',

})

export class App {

  position:string = '';

 

  constructor() {

    Observable.fromEvent(document, 'mousemove')

        .map(evt=>'x=' + evt.x + ' y=' + evt.y)

        .subscribe(val => {

          this.position = val;

     });

  }

}

Check out the Plunker

Here, we are creating an Observable from the ‘mousemove’ event and displaying the x/y coordinates. This will do for demonstration purposes, but in a real world scenario the data might be from a socket, for example.

The problem with the above is that we are not cleaning up our Observable. The goal is to make sure that when the user leaves the view, that the Observable does not remain active, which creates a leak.

So let’s do that. When we subscribe to an Observable, a Subscription is returned which contains an unsubscribe method. Taking advantage of the ngOnDestroy hook, we will add a call to the unsubscribe method as seen below.

export class App implements OnDestroy   {

  position:string = '';

  subs:Subscription;


  constructor() {

    Observable.fromEvent(document, 'mousemove')

        .map(evt=>'x=' + evt.x + ' y=' + evt.y)

        .subscribe(val => {

          this.position = val;

          console.log(val)

        });

  }

 
  ngOnDestroy() {

    this.subs.unsubscribe();

  }

Check out the Plunker.

Although we are now cleaning up our Observable, doing it this way makes it a bit tedious. What if there was a way to let Angular deal with this? It turns out there is, and it’s called the async pipe.

@Component({

  selector: 'my-app',

  template: '<h2>Mouse Position: {{position | async}}</h2>',

})



export class App {

  position:Observable<string>;



  constructor() {

    this.position = Observable.fromEvent(document, 'mousemove')

                                                       .map(evt=>'x=' + evt.x + ' y=' + evt.y);

    }

}

Check out the Plunker.

The async pipe takes an Observable (or Promise), so we reference our position Observable and pass it to the async pipe in the template. Now, we do not need to worry about leaks or have to implement any Angular 2 hooks. Getting in the habit of using the async pipe (or even creating custom pipes) allows us not to worry, or forget about cleaning up our Observables. 

As a side note, we can also display object values with the async pipe. By surrounding the Observable and async pipe in in parentheses, we can access object properties. We also need to use the Elvis (?) operator because in our case there are no values until the mouse is moved.

@Component({

  selector: 'my-app',

  template: '<h2>Mouse Position: x= {{(position | async)?.x}} y= {{(position | async)?.y}} </h2>',

})

 

export class App {

  position:Observable<any>;

 

  constructor() {

    this.position = Observable.fromEvent(document, 'mousemove')

                              .map(evt=>({x:evt.x, y:evt.y}));

    }

}

Check out the Plunker

But, what about the Angular http service? Well, by using the service out of the box there is no need to unsubscribe. The service cleans up after itself. When the XHR result is received, the subscription’s complete method is called and therefore unsubscribes.

There is a case for calling the unsubscribe method on the http service’s returned Observable. If we ever wanted to cancel our on going HTTP request we would call unsubscribe. This calls abort under the covers to complete the clean up.

Sign up for our Angular Course

Learn the most recent version and start building your own Angular apps

view course details