puddlejumper26 / blogs

Personal Tech Blogs
4 stars 1 forks source link

Creating, subscribing to Observables in Angular #62

Open puddlejumper26 opened 4 years ago

puddlejumper26 commented 4 years ago

Guidelines

============================================

Angular uses observables extensively in the event system and the HTTP service.

1.0 Definition

2.0 Compared with Promise

Type Return Value Cancelable
Promises One No
Observables Multi Yes

3.0 Push vs pull

A key thing to understand when using observables is that observables push.

Push and pull are two different ways that describe how a data producer communicates with the data consumer.

Pull consumer decides when to get data from data producer
Push Data producer decides when to give data to data consumer

Every javascript function uses the pull. Promises are the most common way of push in JavaScript today.

4.0 In Angular

Here is the example of setting up HTTP requests.

import { Observable } from "rxjs/Rx"
import { Injectable } from "@angular/core"
import { Http, Response } from "@angular/http"

@Injectable()
export class HttpClient {

    constructor(
        public http: Http
    ) {}

    public fetchUsers() {  <===   here is a simple fetchUsers method of HttpClient returns an observable
        return this.http.get("/api/users").map((res: Response) => res.json())
    }
}

The purpose is to display the users in some sort of list.

! Since this method returns an observable we have to subscribe to it. In Angular we can subscribe to an observable in two ways:

4.1 Subscribe Manner 1

import { Component } from "@angular/core"
import { Observable } from "rxjs/Rx"

// client
import { HttpClient } from "../services/client"

// interface
import { IUser } from "../services/interfaces"

@Component({
    selector: "user-list",
    templateUrl:  "./template.html",
})
export class UserList {

    public users$: Observable<IUser[]>

    constructor(
        public client: HttpClient,
    ) {}

    // do a call to fetch the users on init of component
    // the fetchUsers method returns an observable
    // which we assign to the users$ property of our class
    public ngOnInit() {
        this.users$ = this.client.fetchUsers()
    }
}
<!-- We use the async pipe to automatically subscribe/unsubscribe to our observable -->
<ul class="user__list" *ngIf="(users$ | async).length">
    <li class="user" *ngFor="let user of users$ | async">
        {{ user.name }} - {{ user.birth_date }}
    </li>
</ul>
+Using the dollar sign in the name of a variable that is an observable, is considered best practice. This way it’s easy to identify if your variable is an observable or not.

4.2 Subscribe Manner 2

import { Component } from "@angular/core"

// client
import { HttpClient } from "../services/client"

// interface
import { IUser } from "../services/interfaces"

@Component({
    selector: "user-list",
    templateUrl:  "./template.html",
})
export class UserList {

    public users: IUser[]

    constructor(
        public client: HttpClient,
    ) {}

    // do a call to fetch the users on init of component
    // we manually subscribe to this method and take the users
    // in our callback
    public ngOnInit() {
        this.client.fetchUsers().subscribe((users: IUser[]) => {

            // do stuff with our data here.
            // ....

            // asign data to our class property in the end
            // so it will be available to our template
            this.users = users
        })
    }
}
<ul class="user__list" *ngIf="users.length">
    <li class="user" *ngFor="let user of users">
        {{ user.name }} - {{ user.birth_date }}
    </li>
</ul>

Method 2 Keeping your subscriptions open while not using them is a memory leak and therefore not good.

5.0 Creating a self observable

import { Observable } from "rxjs/Observable"

// create observable
const simpleObservable = new Observable((observer) => {

    // observable execution
    observer.next("bla bla bla")
    observer.complete()
})

// subscribe to the observable
simpleObservable.subscribe()

// dispose the observable
simpleObservable.unsubscribe()

5.1 Creating observables

Creating observables is easy, just call the new Observable() and pass along one argument which represents the observer. Therefore it's usually called “observer” as well.

5.2 Subscribing to observables

Remember, observables are lazy. If you don’t subscribe nothing is going to happen. It’s good to know that when you subscribe to an observer, each call of subscribe() will trigger it’s own independent execution for that given observer. Subscribe calls are not shared among multiple subscribers to the same observable.

5.3 Executing observables

The code inside an observables represents the execution of the observables. On the parameter that was given when creating the observable there are three functions available to send data to the subscribers of the observable:

Calls of the next are the most common as they actually deliver the data to it’s subscribers. During observable execution there can be an infinite calls to the observer.next(), however when observer.error() or observer.complete() is called, the execution stops and no more data will be delivered to the subscribers.

Example

observable.service.ts

import {Observable} from 'rxjs/Observable';

export class ObservableService{
  newService(): Observable<Date>{
    return new Observable (                        <=======
      observer => {
        setInterval(()=>observer.next(new Date()),1000);
      }
    );
  }
}

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import {ObservableService} from "./obervable.service";

@NgModule({
  imports:      [ BrowserModule  ],
  declarations: [ AppComponent ],
  providers:    [ObservableService],     <========
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

app.component.ts

import { Component } from '@angular/core';
import {ObservableService} from "./obervable.service";

@Component({
  selector: 'my-app',
  templateUrl: `Current time: {{currentTime | date: 'mediumTime'}}`,
  providers: [ ObservableService ],
})
export class AppComponent  {
  currentTime: Date;

  constructor(private observableService: ObservableService){
    this.observableService.newService().subscribe(data => this.currentTime = data);
  }
}

References

[1] https://medium.com/@luukgruijs/understanding-creating-and-subscribing-to-observables-in-angular-426dbf0b04a3