Angular 中的可觀察對象

EventEmitterHTTPAsync 管道路由器 (router)響應式表單 (reactive forms)參考文獻javascript

Angular 使用可觀察對象做爲處理各類經常使用異步操做的接口。好比:css

  • EventEmitter 類派生自 Observable
  • HTTP 模塊使用可觀察對象來處理 AJAX 請求和響應。
  • 路由器和表單模塊使用可觀察對象來監聽對用戶輸入事件的響應。

EventEmitter

Angular 提供了一個 EventEmitter 類,它用來經過組件的 @Output() 裝飾器 發送一些值。EventEmitter 擴展了 RxJS Subject,並添加了一個 emit() 方法,這樣它就能夠發送任意值了。當你調用 emit() 時,就會把所發送的值傳給訂閱上來的觀察者的 next() 方法。 咱們來查看一下該類的定義:html

export declare class EventEmitter<T extends anyextends Subject<T{
    /**
     * Creates an instance of this class that can
     * deliver events synchronously or asynchronously.
     *
     * @param isAsync When true, deliver events asynchronously.
     *
     */

    constructor(isAsync?: boolean);
    /**
     * 發出包含給定值的事件。
     */
    emit(value?: T): void;
    /**
     *註冊此實例發出的事件的處理程序。
     */
    subscribe(generatorOrNext?: any, error?: any, complete?: any): Subscription;
}
複製代碼

EventEmitter 與指令@Output 一塊兒在組件中使用以同步或異步方式發送自定義事件,並經過訂閱實例來註冊這些事件的處理程序。 java

接下來咱們演示一個案例,在組件之間傳遞數據。react

子組件 zippy.component.tsweb

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


@Component({
  selector'app-zippy',
  templateUrl'
    <div class="zippy">
      <div (click)="toggle()">點擊該文本</div>
      <div [hidden]="visible">
        <ng-content></ng-content>
      </div>
    </div>
  '

})
export class ZippyComponent implements OnInit {
  visible = true;
  // tslint:disable-next-line: no-output-native
  @Output() open = new EventEmitter<any>();
  // tslint:disable-next-line: no-output-native
  @Output() close = new EventEmitter<any>();

  constructor() { }

  ngOnInit(): void {
  }

  toggle() {
    this.visible = !this.visible;
    if (this.visible) {
      this.close.emit('關閉');
    } else {
      this.open.emit('打開');
      this.open.subscribe((data) => {
        console.log('open subscribe:' + data);
      });
    }
  }
}
複製代碼

父組件 home4.component.tsapi

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

@Component({
  selector'app-home4',
  templateUrl'
    <app-zippy (open)="onOpen($event)" (close)="onClose($event)">我是home組件的內容</app-zippy>
  '

})
export class Home4Component implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

  onOpen(e) {
    console.log(e);
  }

  onClose(e) {
    console.log(e);
  }
}
複製代碼

運行項目,在頁面上點擊文本內容,注意觀察控制檯輸出的內容。以下圖所示:服務器

上文中關於 ng-content 標籤的使用,感興趣的朋友能夠去閱讀一下:Angular開發實踐(八): 使用ng-content進行組件內容投射app

HTTP

Angular 的 HttpClient 從 HTTP 方法調用中返回了可觀察對象。例如,http.get(‘/api’) 就會返回可觀察對象。相對於基於承諾(Promise)的 HTTP API,它有一系列優勢:異步

  • 可觀察對象不會修改服務器的響應(和在承諾上串聯起來的 .then() 調用同樣)。反之,你能夠使用一系列操做符來按需轉換這些值。
  • HTTP 請求是能夠經過 unsubscribe() 方法來取消的。
  • 請求能夠進行配置,以獲取進度事件的變化。
  • 失敗的請求很容易重試。

關於講解數據交互那一部份內容時,對於 get、post 請求都有測試案例,如今回頭看當時比較疑惑的內容,如今就豁然開朗了。

Async 管道

AsyncPipe 會訂閱一個可觀察對象或承諾,並返回其發出的最後一個值。當發出新值時,該管道就會把這個組件標記爲須要進行變動檢查的(譯註:所以可能致使刷新界面)。

下面的例子把 time 這個可觀察對象綁定到了組件的視圖中。這個可觀察對象會不斷使用當前時間更新組件的視圖。

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

@Component({
  selector'app-asyncpipe',
  templateUrl'
    <div><code>observable|async</code>:
      Time: {{ time | async }}</div>

  '

})
export class AsyncpipeComponent implements OnInit {

  time: Observable<any>;
  constructor() { }

  ngOnInit(): void {
    this.time = new Observable(observer => {
      setInterval(() => {
        observer.next(new Date().toString());
      }, 1000);
    });
  }

}
複製代碼

這樣寫就至關於訂閱了 time,會實時接收 next 過來的值,Observable 定義如上,用來逐秒打印時間,頁面接收的值類型爲 Observable。

頁面測試效果:

observable|async: Time: Tue Apr 14 2020 09:39:46 GMT+0800 (中國標準時間)
複製代碼

如果要接收 object 對象,須要這樣取值。

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

@Component({
  selector'app-asyncpipe',
  templateUrl'
    <ng-container *ngIf="time2 |async as tim">
      <div>
        {{tim.date}}---{{tim.time}}
      </div>
    </ng-container>
  '

})
export class AsyncpipeComponent implements OnInit {

  time2: Observable<any>;
  constructor() { }

  ngOnInit(): void {
      this.time2 = new Observable(observer => {
      setInterval(() => {
        const dd = new Date();
        observer.next({ date: dd.toString(), time: dd.toTimeString() });
      }, 1000);
    });
  }

}
複製代碼

頁面測試結果:

Tue Apr 14 2020 09:49:38 GMT+0800 (中國標準時間)---09:49:38 GMT+0800 (中國標準時間)
複製代碼

路由器 (router)

Router.events 以可觀察對象的形式提供了其事件。 你能夠使用 RxJS 中的 filter() 操做符來找到感興趣的事件,而且訂閱它們,以便根據瀏覽過程當中產生的事件序列做出決定。 例子以下:

import { Router, NavigationStart } from '@angular/router';
import { filter } from 'rxjs/operators';

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

  navStart: Observable<NavigationStart>;

  constructor(private router: Router) {
    // Create a new Observable that publishes only the NavigationStart event
    this.navStart = router.events.pipe(
      filter(evt => evt instanceof NavigationStart)
    ) as Observable<NavigationStart>;
  }

  ngOnInit() {
    this.navStart.subscribe(evt => console.log('Navigation Started!'));
  }
}
複製代碼

ActivatedRoute 是一個可注入的路由器服務,它使用可觀察對象來獲取關於路由路徑和路由參數的信息。好比,ActivatedRoute.url 包含一個用於彙報路由路徑的可觀察對象。結合 Angular基礎知識學習(二)中動態路由的JS跳轉,此處咱們僅須要修改 product-detail.component.ts 文件:

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

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

  constructor(public router: ActivatedRoute) {
  }

  ngOnInit(): void {
    this.router.url.subscribe(url => console.log('The URL changed to: ' + url));
  }

}
複製代碼

頁面測試結果爲:

又好比 ActivatedRoute.queryParams 包含路由跳轉傳遞參數的可觀察對象。仍是結合我以前文章的案例,修改 news.component.ts 文件:

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

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

  nums: any[] = [];

  constructor(public router: ActivatedRoute) {
    this.router.queryParams.subscribe((data) => {
      console.log(data);
    });
  }

  ngOnInit(): void {

  }

}
複製代碼

頁面測試結果爲:

響應式表單 (reactive forms)

響應式表單具備一些屬性,它們使用可觀察對象來監聽表單控件的值。 FormControlvalueChanges 屬性和 statusChanges 屬性包含了會發出變動事件的可觀察對象。訂閱可觀察的表單控件屬性是在組件類中觸發應用邏輯的途徑之一。好比:

import { FormGroup } from '@angular/forms';

@Component({
  selector'my-component',
  template'MyComponent Template'
})
export class MyComponent implements OnInit {
  nameChangeLog: string[] = [];
  heroForm: FormGroup;

  ngOnInit() {
    this.logNameChange();
  }
  logNameChange() {
    const nameControl = this.heroForm.get('name');
    nameControl.valueChanges.forEach(
      (value: string) => this.nameChangeLog.push(value)
    );
  }
}
複製代碼

參考文獻

angular Observable

相關文章
相關標籤/搜索