[Angular] 【Angular 開發實戰:從零開始】 學習筆記 (下)
===
###### tags: `前端` `Angular`
內容僅為個人學習筆記之紀錄分享。
## 課程網址
https://www.udemy.com/course/angular-zero/

【S00~S03筆記】
[[Angular] 【Angular 開發實戰:從零開始】 學習筆記 (上)](https://hackmd.io/@mko123654/BynYbWJcq)
---
## S04重點整理

* **S04-01~S04-4:學習資料繫結方法**
1. 單向-內嵌繫結(Interpolation):
:::info
把compoment裡的屬性值帶到template
EX: {{ property }}
:::
2. 單向-屬性繫結(Property Binding):
:::info
把template內的屬性改成compoment裡的屬性值
EX: [href] = "statement"
若為自訂之attribute
EX: [attr.自訂屬性名] = "statement"
:::
3. 單向-事件繫結(Event Binding):
:::info
template觸發事件,呼叫compoment裡的方法
EX: (event) = "someMethod()"
使用`$event`參數,可在方法的內容內加入傳入參數的判斷
EX: (event) = "someMethod($event)"
使用有型別的`$event`參數
EX: (event) = "someMethod($event: 事件型別)"
:::
4.雙向繫結(Two-way Binding)
:::info
EX: [(ngModel)] = "prperty"
(需imports FormsModule到AppModule內)
:::
* **S04-05 認識範本參考變數 (Template reference variables)**
* 在範本內任意HTML標籤套用 #name 語法
- 會在範本內建立一個名為name的區域變數
- 該name區域變數將會儲存該標籤的DOM物件
- 可以透過「事件繫結」將任意DOM物件內的任意屬性回傳回元件類別(Component class)中
* **S04-06 學習 Angular 元件型指令 (Component Directives)**
* 預設「元件」就是一個含有樣板的指令(最常見) EX:<app-root></app-root>
* **S04-07~S04-08 學習 Angular 屬性型指令 (Attribute Directives)**
* 這種指令會修改元素的外觀或行為,如:
1. NgModel:雙向繫結
1. NgStyle:
```angular=
EX: <h1 [ngStyle]="getStyle()">
EX: <p [ngStyle]="{'font-size' : (16+counter) + 'px' , color : 'red'};>
EX: <p [style.font-size]= "(12+counter)+ 'px'" [style.color]= "'red'">
```
3. NgClass:
```gherkin=
EX: <h1 [ngClass]="{'class名' : boolean}">
EX: <font [ngClass]="{'highlight' : counter%2==0}"> //在css內設定.highlithe的樣式
EX: <font [class.highlight]="counter%2==0">
```
* **S04-09~S04-11 學習 Angular 結構型指令 (Structural Directives)**
* 這種指令會透過新增和刪除DOM元素來改變DOM結構,如:
1. NgIf:
```angular=
EX: <div class="sideBar" *ngIf="boolean">
```
2. NgFor:
```angular=
EX:
<article class="post" id="post{{inx}}}" *ngFor="let item of data; let inx = index;">
<header class="post-header">
<h2 class="post-title">
<a [href]="item.href">{{item.title}}</a>
</h2>
<div class="post-info clearfix">
<span class="post-date"><i class="glyphicon glyphicon-calendar"></i>{{item.date}}</span>
<span class="post-author"><i class="glyphicon glyphicon-user"></i><a href="http://blog.miniasp.com/author/will.aspx">{{item.author}}</a></span>
<span class="post-category"><i class="glyphicon glyphicon-folder-close"></i><a [href]="item['category-link']">{{item.category}}</a></span>
</div>
</header>
<section class="post-body text" [innerHTML]= "item.summary" >
</section>
</article>
3. NgSwitch:(註:前面==不要==加*號)
```angular=
註:用a-ngSwitch新生成的程式碼會出現新的div標籤,可能影響樣式,此時可將標籤改成ng-container
EX:
<div [ngSwitch]="conditionExpression">
<div *ngSwitchCase="expression1">output</div>
<div *ngSwitchCase="expression2">output</div>
<div *ngSwitchDefault>output2</div>
</div>
EX:
<ng-container [ngSwitch]="counter%2">
<ng-container *ngSwitchCase="0">程式碼</ng-container> //餘數為0
<ng-container *ngSwitchCase="1">程式碼</ng-container> //餘數為1
<ng-container *ngSwitchDefault>output2</ng-container> //預設
</ng-container>
```
* **S04-12~S04-18 學習 Angular 使用 Pipes 管線元件**
大多用途在於格式轉換Format,需要時再查API,類似Vue的filter
內建的pipes可以到以下網址查,也可以自訂
https://angular.io/api?query=pipe
* **S04-19 在範本中使用安全導覽運算子 (safe navigation operator)**
```angular=
EX: {{item.subject?.subtitle}}
```
若subject為undefined或Null就不會再去讀取後方的subtitle (只能用在template裡)
* **S04-20 如何避免在範本中出現 TypeScript 型別錯誤**
```angular=
{{item.subject}} 出現認不得subject型別的錯誤
解決方法:
EX: {{item['subject']}} >> 無法檢查,回傳any型別
EX: {{$any(item).subject}} >> 轉換成any型別
```
---
## S05重點整理

* **S05-01 簡介 Angular 元件架構**

* ArticleHeader和ArticleBody為ArticleList的子元件。
* ArticleList為ArticleHeader和ArticleBody的父元件。
* 父元件以【屬性繫結】和子元件溝通
* 子元件以【事件繫結】和父元件溝通
* 為了同種目的的元件可以包成一個獨立的功能模組
* 服務元件可以以DI注入共用的資料或方法進入其他元件內。
* **S05-02 建立 Angular 功能模組**
新增module: 終端機輸入 n g m 模組名稱 -m 要匯入進的模組
```gherkin=
EX: n g m article -m app
```
* **S05-03 將現有 Angular 元件加入功能模組**
==若子module裡的component要讓其他模組看的到,需要子module的exports中匯出==
```gherkin=
EX: n g m 模組名稱
註: 若元件要建立在子模組內(非AppModule)則要cd至指定的位置下
```
* **S05-04 定義 Angular 元件的輸入介面 - @Input()**
父元件傳屬性給子元件: property binding
子元件class內建立屬性,並在directive上寫好property binding
```gherkin=
@Input()
item;
```
* 子元件內:
```angular=
import { Component, OnInit } from 'angular/core'
@Component({
selector: 'app-article-header',
templateUrl: './article-header.component.html'
styleUrls: ['./article-header.component.css']
})
export class ArticleHeaderComponent implements OnInit {
@Input()
item;
constructor() {}
ngOnInit() {}
}
```
* 父元件內:
```angular=
<article class="post" id ="{{idx}}" *ngFor="let item of data; let idx=index"
<app-article-header [item] = "item"></app-article-header>
<app-article-body [item] = "item"></app-article-body>
</article>
```
* **S05-05 介紹 ngOnInit 與 ngOnDestroy 生命週期 Hook**
1. constructor() 為第一個執行的,通常不會寫什麼東西(因為component還沒初始化,會拿不到東西),但會用於DI。
2. ngOnInit() 元件初始化要做的事,EX:執行entry()用axios去打後端,動態得出使用者可選的系統選單選項。
3. 執行屬性繫結、事件繫結...etc。
4. ngOnDestroy() 在元件被銷毀前做某些事(很少用到)。
* **S05-06 定義 Angular 元件的輸出介面 - @Output()**
[以刪除文章為例]
說明:在article-header的部分加入刪除文章的button
按下之後通知父元件article-list要刪除文章,讓父元件實作去刪除其內容,並且傳給article-body
* 子元件內:
```angular=
子元件通知父元件:event binding,子通知父一個事件,並由父來決定實際怎麼做這個事件的方法。
子元件class內建立屬性,並在directive上寫好Event Binding
//生成一個事件發射器,泛型any型別
@Output()
delete = new EventEmitter<any>();
//方法發送事件資料
XX方法() {
this.某事件.emit(傳送的物件);
}
//發送時機
在template內決定。 EX: <button (click)="clickDelete()">
EX:
import { Component, OnInit } from 'angular/core'
@Component({
selector: 'app-article-header',
templateUrl: './article-header.component.html'
styleUrls: ['./article-header.component.css']
})
export class ArticleHeaderComponent implements OnInit {
@Input()
item;
@Output()
delete = new EventEmitter<any>();
constructor() {}
clickDelete() {
this.delete.emit(this.item);
}
ngOnInit() {}
}
```
* 父元件內:
```angular=
監聽來自子元件的delete事件,收到後執行doDelete($event)方法刪掉文章
EX:
【articleListComponent.html內】
<article class="post" id ="{{idx}}" *ngFor="let item of data; let idx=index"
<app-article-header [item] = "item" (delete)="doDelete()"></app-article-header>
<app-article-body [item] = "item"></app-article-body>
</article>
【articleListComponent.ts內】
doDelete(item) {
this.data = this.data.filter( v => {
return v.id !== item.id;
});
}
```
* **S05-07 解釋單向資料流與實作不可變的物件**
* [單向資料流]
資料的變更永遠由上層元件傳往下層元件,切勿在子元件直接修改資料。
* [不可變物件]
一個物件內有任何屬性的更動,即重新建立一個新的物件來取代之。
EX:`const currentForm = Object.assign({}, newForm);`
* **S05-10 介紹 ngOnChanges 生命週期 Hook**
執行的先後順序
`constructor() => ngOnChanges() => ngOnInit()`
ngOnChanges:
* 觸發的時機點:當父類別透過透過Property Binding 將資料傳到子元件,且子元件有透過宣告 @Input() 的變數來接收父類別傳來的資料,子元件的ngOnChange就會被觸發。當父類別的來源資料有異動的時候,也會重新觸發 ngOnChanges()。
---
## S06重點整理

* **S06-01 建立 Angular 服務元件與實作相依注入**
* 輸入`ng g s data`建立一個dataService
```angular=
import { Injectable } from '@angular/core';
@Injectable()
export class DataService{
constructor() {}
}
```
* 在需要使用的元件的providers內加上DataService
```angular=
@NgModule({
imports:[
CommonModule,
FormModule
],
providers:[DataService],
declarations: [ArticleListComponent, ArticleHeaderComponent, ArticleBodyComponent],
exports: [ArticleListComponent]
})
export class ArticleModule{}
```
* 若使用`ng g s data -m article`指定要註冊進articleModule內,則會自動完成providers的註冊
* 相依注入的方式1,在使用元件內宣告一個datasvc屬性,並在construcor內把DataService賦予給datasvc。
```angular=
import { Component, OnInit } from 'angular/core'
impoty { DataService} from '../../data.service'
@Component({
selector: 'app-article-list',
templateUrl: './article-list.component.html'
styleUrls: ['./article-list.component.css']
})
export class ArticleListComponent implements OnInit {
counter = 0
data:Array<any>;
datasvc: DataService;
constructor(datasve: DataService) {
this.datasvc = datasvc;
}
doDelete() {}
ngOnInit() {}
}
```
* 相依注入的方式2,在constructor內,給予private或public的修飾子即可。
```angular=
constructor(private datasvc: DataService{
}
```
* DI完成後使用服務元件的方法:
```angular=
this.datasvc.doSomeFunction();
```
* **S06-02 透過服務元件重構現有元件的程式碼**
* 若要在template裡使用到DI注入的服務元件,該服務元件需要使用public建構子
```angular=
使用的元件內:
constructor(public datasvc: DataService{}
template內:
<article class="post" id ="{{idx}}" *ngFor="let item of datasvc.data; let idx=index"
<app-article-header [item] = "item" (delete)="datasve.doDelete($event)"></app-article-header>
<app-article-body [item] = "item"></app-article-body>
</article>
```
* **S06-03 了解 @Injectable() 裝飾器與注入 HttpClient 服務元件**
若服務元件裡還需要注入其他服務,而該服務來自其他Module裡,則需要將該Module註冊進要"注入該服務元件的module內的imports屬性中",且要在注入服務的class標上@Injectable()。
* **S06-04 學習 HttpClient 基本使用方法 - get()**
```angular==
EX:
constructor(private http: HttpClient){
http.get('http://localhost:8080/api/getData')
.subscribe(result => {
this.data = result;
});
}
```