udemy.angular/docs/observables.md

5.6 KiB

Observables

Observable emmits an event driven by the data source.

Observer subscribe to the observable to be notified when an event is emitted.

This is an asynchronous operation.

component

It can also used promises or callbacks to achieve the same result. Observable is just an other approach.

Install RxJS

npm install --save rxjs@6

npm install --save rxjs-compat

Example and general usage

In this case params is an observable which we can subscribe to.

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
  id: number;

  constructor(private route: ActivatedRoute) {
  }

  ngOnInit() {
    this.route.params.subscribe((params: Params) => {
      this.id = +params.id;
    });
  }
}

It exists various types of observable.

  • executed once
  • executed periodically
  • ...
import { interval } from 'rxjs';

interval(1000).subscribe( count => {
    consol.log(count);
})

interval is a built-in observable from rxjs.

If the app don't unsubscribe from the observable can cause memory leaks. Also, if we navigate to an other route, countless observable will be created and couses performance issues.

When we leave the component we can call the OnDestroy function to unsubscribe from the observable.

import { Component, OnDestroy, OnInit } from '@angular/core';

import { interval, Subscription, Observable } from 'rxjs';

@Component({
    selector: 'app-home',
    templateUrl: './home.component.html',
    styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit, OnDestroy {

    private firstObsSubscription: Subscription;

    constructor() {}

    ngOnInit() {
    this.firstObsSubscription = interval(1000).subscribe(count => {
        console.log(count);
    });

    ngOnDestroy(): void {
        this.firstObsSubscription.unsubscribe();
    }
}

In this example, the first subscription is stored in firstObsSubscription variable, which at leaving the component will be destroyed by calling unsubscribe().

Note: For all Angular built-in observables, is not necessary to unsubscribe from the observable. This is handleb by Angular itself.

Building an observable (data, error, complete)

const customIntervalObservable = Observable.create(observer => {
    let count = 0;
    setInterval(() => {
    observer.next(count);
    if (count === 5) {
        observer.complete();
    }
    if (count > 3) {
        observer.error(new Error('Count is greater 3!'));
    }
    count++;
    }, 1000);
});

this.firstObsSubscription = customIntervalObservable.subscribe(data => {
    console.log(data);
}, error => {
    console.log(error);
    alert(error.message);
}, () => {
    console.log('Completed!');
});

The subscribe function accepts up to three arguments: data, error and complete.

Note: if the observable is completed, is not necessary to unsubscribe.

Note: If an error is thrown, the observable is cancelled but not completed.

Operators

Operators are grate to transform our data. The application can then subscribe to the result of the operator. On the operator can be called the pipe() function. Every operator has such a method. This function depends on the rxjs/operators pakage.

component

This is usefull when the application is fetching data from the server and it should trandformed before the component will use it.

Subjec

Subject from RxJS is a more active then the event emitter because it can be called the function next() from the outside.

component

Subject is the recommended way to emit events.

Subject Example

user.service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({providedIn: 'root'})
export class UserService {
  activatedEmitter = new Subject<boolean>();
}

app.component.ts

import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';

import { UserService } from './user.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
  userActivated = false;
  private activatedSub: Subscription;

  constructor(private userService: UserService) {
  }

  ngOnInit() {
    this.activatedSub = this.userService.activatedEmitter.subscribe(didActivate => {
      this.userActivated = didActivate;
    });
  }

  ngOnDestroy(): void {
    this.activatedSub.unsubscribe();
  }
}

app.component.html

...
<p *ngIf="userActivated">Activated!</p>
...

user.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';

import { UserService } from '../user.service';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
  id: number;

  constructor(private route: ActivatedRoute, private userService: UserService) {
  }

  ngOnInit() {
    this.route.params.subscribe((params: Params) => {
      this.id = +params.id;
    });
  }

  onActivate() {
    this.userService.activatedEmitter.next(true);
  }
}

user.component.html

<button class="btn btn-primary" (click)="onActivate()">Activate</button>

Ressource

RxJS