[Angular] 【Angular 開發實戰:從零開始】 學習筆記 (下) === ###### tags: `前端` `Angular` 內容僅為個人學習筆記之紀錄分享。 ## 課程網址 https://www.udemy.com/course/angular-zero/ ![](https://i.imgur.com/PFcZW8R.png) 【S00~S03筆記】 [[Angular] 【Angular 開發實戰:從零開始】 學習筆記 (上)](https://hackmd.io/@mko123654/BynYbWJcq) --- ## S04重點整理 ![](https://i.imgur.com/9ACAge6.png) * **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重點整理 ![](https://i.imgur.com/pozuV2a.png) * **S05-01 簡介 Angular 元件架構** ![](https://i.imgur.com/819bq4Z.png) * 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重點整理 ![](https://i.imgur.com/rWFfFjc.png) * **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; }); } ```