建立新專案 用Agnular CLI
ng new => 會問專案名稱 輸入APM
路徑 C:\Test\ng new 這樣產生出來的會是 C:\Test\APM\src
src資料夾下預設會有app資料夾
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule], //載入Module , 包含第三方套件 , 自己寫的
declarations: [AppComponent], //載入Component
bootstrap: [AppComponent] //設定啟動的Component
})
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'APM';
}
..\index.html
<html>
<head></head>
<body>
<app-root></app-root>
</body>
</html>
用npm 安裝 ref NPM 新手教學 , npm init ,npm Install , package-lock.json
npm i bootstrap font-awesome
可以在 ..\styles.css 加上
@import "~bootstrap/dist/css/bootstrap.min.css";
@import "~font-awesome/css/font-awesome.min.css";
未知 這樣可以找到路徑?
用Agnular CLI 建立component ( 會自動加入參考 )
ng g c products\product-list
C:\Test\APM\src\app\products\
product-list.component.ts
product-list.component.html
建立 product-detail Component
ng g c products/product-detail --flat ( 加上 --flat 就不會建立product-detail資料夾 直接產生到products資料夾 )
built-in directive
*ng**** 是屬於BrowserModule在app.module.ts時有載入 所以才能用
*ngIf 可以控制 div 是否顯示
*ngFor='let item of list' 類似foreach
Property Binding
<img
[src]='item.imageUrl'
title="name is {{ item.productName }}"
[style.width.px]='imageWidth'
[style.margin.px]='imageMargin'
/>
Event Binding ref Event reference
<button class="btn btn-primary" (click)="toggleImage()">
{{showImage ? 'Hide' : 'Show'}} Image
</button>
Two-way Binding [()] Banana in a Box --哪裡像了T_T
<input type="text" [(ngModel)]="listFilter" />
<h4>Filtered by: {{ listFilter }}</h4>
效果就是 輸入文字後 h4 同時改變
two-way binding 需要載入 app.module.ts
import { FormsModule } from "@angular/forms";
Pipe ref Pipe , DatePipe , CurrencyPipe
資料在顯示之前可以做處理 轉大小寫 ,日期 ,金錢格式
<td>{{ item.productCode | lowercase }}</td>
<td>{{ item.releaseDate | date: "yyyy/MM/dd" }}</td>
<td>{{ item.price | currency: "USD":"symbol":"1.2-2" }}</td>
Custom Pipe ref Custom pipes ,
ng g pipe app\shared\ConvertToSpacesPipe
Interfaces 給物件強行別 這樣就有提示 包含html
Component 的 style 是獨立的不會影響到別的Component
Component Lifecycle ref lifecycle-hooks , Lifecycle Hooks 學習筆記 (一) , [Angluar 大師之路] Day 04 - 認識 Angular 的生命週期
Oninit 跟 建構子 的差異
建構子 就是拿來 注入服務
Oninit 拿來取得內容像是call api 拿下拉選單的資料
Component 可以在套Component 也可以傳遞參數
外面Component
<td><app-star [rating]="item.starRating"></app-star></td>
裡面Component ( app-star )
@Input() rating: number;
必須要加Input 才能接到外面傳來的值
裡面Component ( app-star ) 也可以傳值到外面的Component
@Output() ratingClicked: EventEmitter<string> = new EventEmitter<string>();
onClick(): void {
this.ratingClicked.emit(`The rating ${this.rating} was clicked!`);
}
外面的Component
<app-star [rating]="item.starRating" (ratingClicked)="onRatingClicked($event)"></app-star>
onRatingClicked(message: string): void {
alert(message);
}
說明一下 EventEmitter 的泛型是string 因為回傳內容是字串 ( 訂閱事件的概念 觸發 emit 就會往上呼叫 )
當 onClick 被觸發後 ratingClicked emit 叫外面的Component onRatingClicked 接收 The rating ${this.rating} was clicked!
就會被alert
建立Service
ng g s products\products
Angular 6 之後 可以用
@Injectable({
providedIn: "root"
})
用 HttpClient 跟 RxJS 跟API 拿資料
RxJS 是另一個要學習的請看 30 天精通 RxJS , RxJS in Angular: Reactive Development
product-list.component.ts
ngOnInit() {
this.productsService.getProducts().subscribe({
next: products => {
this.products = products;
console.log("products length =>" + products.length);
this.filteredProducts = this.products;
},
error: err => (this.errorMessage = err)
});
console.log("OnInit done");
}
products.service.ts
getProducts(): Observable<IProduct[]> {
return this.http.get<IProduct[]>(this.productUrl).pipe(
tap(data => console.log("pipe pipe")),
catchError(this.handleError)
);
}
結果如上 , 所以RxJS是支援非同步的 這邊只是想說 這裡坑真的很大
Routing Basics
app.component.ts
import { RouterModule } from "@angular/router";
RouterModule.forRoot([
{ path: "products", component: ProductListComponent },
{ path: "products/:id", component: ProductDetailComponent },
{ path: "welcome", component: WelcomeComponent },
{ path: "", redirectTo: "welcome", pathMatch: "full" },
{ path: "**", redirectTo: "welcome", pathMatch: "full" }
])
注意先後順序 匹配到就不會往下囉
app.component.html
<nav class="navbar navbar-expand navbar-light bg-light">
<ul class="nav nav-pills">
<li><a class="nav-link" routerLinkActive="active" [routerLink]="['/welcome']">Home</a></li>
<li><a class="nav-link" routerLinkActive="active" [routerLink]="['/products']">Product List</a></li>
</ul>
</nav>
<div class="container">
<router-outlet></router-outlet>
</div>
改成用Router後之前 @Component => selector 就不需要 ( 指的是頁面的進入點 因為被 router-outlet 取代)
設定好之後 流程如下
點連結 [routerLink]="['/products']"
RouterModule.forRoot 找到 { path: "products", component: ProductListComponent }
把ProductListComponent的內容放到<router-outlet></router-outlet>
直接打網址 localhost:4200/item
RouterModule.forRoot 找到 { path: "**", redirectTo: "welcome", pathMatch: "full" } => 因為沒有所以會被"**"匹配成功
把WelcomeComponent 的內容放到<router-outlet></router-outlet>
Routing Basics 2
產品列表 連結到 產品明細頁
<a [routerLink]="['/products', item.productId]">
{{ item.productName }}
</a>
RouterModule.forRoot([
{ path: "products/:id", component: ProductDetailComponent },
product-detail.component.ts
import { ActivatedRoute, Router } from '@angular/router';
constructor(private route: ActivatedRoute, private router: Router) { }
ngOnInit() {
const id = +this.route.snapshot.paramMap.get('id');
this.pageTitle = 'Product Detail' + id;
}
onBack(): void {
this.router.navigate(['/products']);
}
要接受參數需要ActivatedRoute , 加入回上一頁的功能需要Router
Router Guards ref Router Guards
管理連結是否可進入 像是沒有登入不能進入後台....等
舉例
CanActivate : 進入 頁面前檢查
CanDeactivate : 離開 頁面前檢查
CLI 產生
ng g g products/product-detail
product-detail.guard.ts
constructor(private router: Router) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
// product/1
// [0] [1]
const id = +next.url[1].path;
if (isNaN(id) || id < 1) {
alert('Invalid product Id');
this.router.navigate(['/products']);
return false;
}
return true;
}
回傳簡單就是 true 可進入 , false不可以
分開 Module ref 透過Module組織管理你的程式
建立ProductModule
ng g m products/product --flat -m app
--flat 表示不建立product 資料夾
-m 表示import到 app.module
建立SharedModule
ng g m shared/shared --flat -m products/product.module
--flat 表示不建立shared 資料夾
-m 表示import到 product.module
shared module 可以把常用的module exports出來 這樣大家都可以用
像是 CommonModule, FormsModule , StarComponent
整理一下
- 不要重複 imports component
- 模組沒有繼承的概念
- CommonModule 可以用*ngIf ..等
- 外面模組是不能用內部模組的 要放到exports
ProductModule import SharedModule
ProductModule 預設是不能用 StarComponent 要用的話就要
exports: [ StarComponen t]
這裡挺亂的需要再加強
CLI 技巧
ng g c hello -d
不會真的產生檔案 可以預覽產生的路徑是否是你想要的 需不需要 --flat
ng b --prod 會產生dist資料夾
遇到IIS 由root網址進去ok 但是F5就404
可以看
如何將 Angular 2 含有路由機制的 SPA 網頁應用程式部署到 IIS 網站伺服器
如果內容有誤請多鞭策謝謝