Decorators

Decorators 是 function 掛有 @前綴符號,可以用於 classparamemtermethodproperty的前面。用來提供額外的資訊。

HostListener

@hostListener 可以監聽宿主元素上的事件,監聽 JS 的 event click | keydown | mouseleave …

1
2
3
4
5
6
7
8
class CountClicks {
numberOfClicks = 0;
// 這裡的 onClick 可以自行命名
@HostListener("window:click", ["$event"])
onClick(btn): void {
console.log("button", btn, "number of clicks:", this.numberOfClicks++);
}
}

HostBinding

@HostBinding()可以為指令的宿主元素新增類、樣式、屬性等

@HostBinding()和@HostListener()不僅僅用在自定義指令,只是在自定義指令中用的較多

下面我們通過實現一個在輸入時實時改變字型和邊框顏色的指令,學習@HostBinding()和@HostListener()的用法。

1
2
3
4
5
6
7
8
9
10
export class AddRainbowDirective {
constructor() {}
possibleColors = ["darksalmon", "hotpink", "lightskyblue", "goldenrod", "peachpuff", "mediumspringgreen", "cornflowerblue", "blanchedalmond", "lightslategrey"];
@HostBinding("style.color") color: string;
@HostBinding("style.borderColor") borderColor: string;
@HostListener("keydown") onKeydown() {
const colorPick = Math.floor(Math.random() * this.possibleColors.length);
this.color = this.borderColor = this.possibleColors[colorPick];
}
}
1
<input appRainbow />

NgModule

  • declarations-屬於此 NgModule 的 Component、Directive 與 Pipe 皆放置於此。
  • imports-此 NgModule 需要使用、依賴的其他 NgModule 皆放置於此(好像有點饒舌)。
  • providers-可以被整個應用程式中的任何部分被使用的 Service 皆放置於此,也可以將 Service 直接放置在 Component 的 Metadata 裡的  providers (但放置在不同地方會有一些需要特別注意的事項,後續在說明 Service 時會提到。另外,在 Angular 6 之後,在 Service 之中也可以使用 Metadata 裡的  providedIn  宣告,該 Service 要  provided  到哪裡。詳細可以參考此篇文章或是隔壁棚Angular 大師之路也有提到) 。
  • exports-此處放置的是,當在其他 NgModule 裡 import 了當前的 Module 後,可以在其他 NgModule 裡的 Component Template 使用的 Component、Directive 與 Pipe。
  • entryComponents-放在這裡的元件通常是用不通過 Route 的方式,而採用動態加入的元件。
  • bootstrap-在此設置的是應用程式通常稱之為 Root Component (根元件) ,而且只有 Root Module 才要設置此屬性。

[功能介紹-11] NgModules - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天

Input

父層的 html

1
<app-bank-account [bank]="RBC" [account-id]="4747"></app-bank-account>

子層的 component

1
2
3
4
5
class BankAccount {
@Input() bankName: string;
@Input("account-id") id: string; //可以用此方把名稱改為自已想要的東西
// TODO: 還有一個可以直接 set() 值
}

Output

要使用 output 有三個步驟

  1. 引入 Output & EventEmitter 的 function 在 angular
  2. 讓你的 Output 有一個 EventEmitter
  3. 建立一個 function 把資料 emt 上去
1
2
3
4
5
6
7
8
9
import { Output, EventEmitter } from '@angular/core'; // step1

@Output() newItemEvent = new EventEmitter<string>(); // step2

addNewItem(value: string) {
this.newItemEvent.emit(value); // step3 用這個方式 emit 資料上去
}
}
// html <app-item (newItemEvent)="addItem($event)"></app-item>

VeiwChild

抓取 DOM 也可以抓取 component 得到裡面的定義變數的值

1
2
3
4
5
6
7
@ViewChild('historyBlock') historyBlock;

ngOnInit(): void {
console.log(this.historyBlock.nativeElement) // get DOM
}
// html
<div #historyBlock> </div>

VeiwChildren

用於配置檢視查詢的引數裝飾器。

1
2
3
<ng-container *ngFor="let item of arrName">
<hello #item [name]="item"></hello>
</ng-container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { AfterViewInit, Component, VERSION, ViewChild } from "@angular/core";
import { HelloComponent } from "./hello.component";

@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
})
export class AppComponent implements AfterViewInit {
arrName = ["aa", "bb", "cc"];
@ViewChildren("item") itemElement: QueryList<HelloComponent>;

ngAfterViewInit() {
this.itemElement.map((e) => {
console.log("itemElement", e.name); // 依序提出子組件裡的值
});
}
}

注意:ViewChildren  一定要搭配  QueryList  一起使用,不然就不能實現列表更新這件事了因生命週期關係  ViewChild  與  ViewChildren  要在  ngAfterViewInit  裡才能實現

Injectable & Inject

Angular 其實提供了三種註冊 Service 的方式。

inject 第一種

第一種方式最簡單,也是 Angular CLI 在產生 Service 時預設使用的方式:

這種方式是在 Service 自己的 Metadata 裡加上 providedIn: 'root' 的屬性,來告訴 Angular 說:「請把我註冊在整個系統都是使用同一個實體的注射器裡」。

1
2
3
@Injectable({
providedIn: 'root'
})

inject 第二種

這種方式是告訴 Angular 說:「請把我註冊在這整個 NgModule 都用同一個實體的注射器裡」。也就是說,假設當初 A Service 是註冊在 A Module 裡,那麼在整個 A Module 裡就會使用同一個實體。

1
2
3
4
5
6
7
@NgModule({
providers: [
BackendService,
Logger
],
...
})

那在 B Module 裡可以用 A Service 嗎? 可以。

那在 B Module 裡的 A Service 跟在 A Module 裡的 A Service 是同一個實體嗎?同一個<心中存疑??>

inject 第三種

這種方式是告訴 Angular 說:「請把我註冊在這整個 Component 都用同一個實體的注射器裡」。意思是每個 Component 拿到的 Service 實體都不是同一個。

絕對不是同一個

1
2
3
4
5
@Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})

這個要常常看一下,重要

https://blog.kevinyang.net/2018/01/19/angular-viewproviders-providers/

參考文章

自訂 Decorators

HostBinding&HostListener

HostBinding&HostListener