目前是 4.0.0-rc.2.
剛好有個小項目要開發,就直接拿它來試水啦.
更新 cli 到最新版, 創建項目, 然后 follow https://github.com/angular/angular/blob/master/CHANGELOG.md 升級去 4.0
遇到一個 error https://github.com/angular/angular-cli/issues/5131
更新 typescript 就可以了.
一些新功能和 break change
1. template 替換成 ng-template 了
<template #loading>Loading...</template> <!--棄用了--> <ng-template #loading>Loading...</ng-template> <!--新的用這個-->
2. if else 增強
<ng-template #loading>Loading...</ng-template> <div *ngIf="user$ | async; else loading; let user"> {{ user.name }} </div>
我們可以很容易的寫出這種等待 ajax 資料的代碼.
let user 獲取到的就是 user$.next 的 value 啦, loading 則是對應一個 ng-template.
RC.5 更新 (一如往常, ng 在 RC 階段依然可以加入新功能和 breaking change. 厲害吧)
ngIf 和 ngFor 微語法新加入了 "as" 這個詞法.
之前 *ngIf="user$ | async; else loading;let user"
之后 *ngIf="user$ | async as user; else loading"
取代了 let, 好處就是, 語義比較有連貫,比較熟悉.
ngFor 也可以
<!--之前--> <div *ngFor="let item of ['a','b','c'] as items; let i = index"> {{item}} {{items.length}} {{i}} </div> <!--之后, 使用 as 替代了 let--> <div *ngFor="let item of ['a','b','c'] as items; index as i"> {{item}} {{items.length}} {{i}} </div> <!--之后, 使用逗號","也可以哦 --> <div *ngFor="let item of ['a','b','c'] as items, index as i"> {{item}} {{items.length}} {{i}} </div>
3. Replace references to TrackByFn
to TrackByFunction<any>
4. Validators.email
this.form = this.fb.group({ email : ["", Validators.email] }); let emailCtrl = this.form.get("email"); console.log(emailCtrl.valid); //fail emailCtrl.setValue("hengkeat87@gmail"); console.log(emailCtrl.valid); //ok emailCtrl.setValue("hengkeat87@gmail.com"); console.log(emailCtrl.valid); //ok
這個沒什么意義, 相信大家早就自己實現了. 應該是做給那些老師方便他們寫 demo 教學生的吧...
5. Validators.equalsTo
this.form = this.fb.group({ password : ["",Validators.equalsTo("confirmPassword")], confirmPassword : [""] });
bug : https://github.com/angular/angular/issues/14770
實現源碼 : https://github.com/angular/angular/commit/7b7ae5f
這個相信大家也自己實現了,
記得上次自己寫的時候也是遇到 bug /.\
6. Select option [compareWith]
<form [formGroup]="form"> <select [compareWith]="compareModel" formControlName="data" > <option *ngFor="let item of items; trackBy:trackBy" [ngValue]="item" >{{ item.text }}</option> </select> </form>
type Item = { Id: number, value: string, text: string }; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { constructor( private fb: FormBuilder ) { } form: FormGroup items: Item[] trackBy: TrackByFunction<Item> = (index, item) => { return item.Id; } compareModel(a: Item, b: Item) { return a.Id === b.Id; } ngOnInit() { this.form = this.fb.group({ data: [null] }); this.items = [ { Id: 1, value: "a", text: "A" }, { Id: 2, value: "b", text: "B" }, { Id: 3, value: "c", text: "C" } ]; //this.form.get("data").setValue(this.items[0]); // 在沒有 compareWith 的情況下,我們必須放回相同 reference 的對象 this.form.get("data").setValue({ Id: 1, value: "a", text: "A" }); //在設置 compareWith 后,我們可以給不同 reference 的對象 } }
關鍵就看最后兩行的注釋.
7. router runGuardsAndResolvers
imports: [RouterModule.forRoot([ { path: 'home', component: HomeComponent }, { path : "about", component : AboutComponent, runGuardsAndResolvers : "always", //"always" || "paramsChange" || "paramsOrQueryParamsChange" 選擇不同的檢測時機 canActivate : [GuardService] }, { path : "", redirectTo : "home", pathMatch : "full" } ])],
通過 runGuardsAndResolvers 我們可以設置更多的守衛檢查時機 (2.x版本只有在進入 route 的時候檢查, 如果之后只是修改 params or queryParams 守衛是不會再檢測的), paramsChange 指的是 matrix.
8. RouteConfigLoadStart | RouteConfigLoadEnd
route 多了2個 event
當一個 module 被加載 ( preload 也可以) 時就會觸發. 主要用途是讓我們知道 preload module 加載開始和完成了, 2.x 我們沒法監聽到.
9. Renderer 換成 Renderer2 了.
10.
OpaqueToken 沒有了, 改成 InjectionToken<T>
Injector.get 也有點更換, 支持類型了
let service = this.injector.get<T>(token: Type<T>|InjectionToken<T>, notFoundValue?: T): T;
以上的 T 必須是同一個類型哦. 雖然我放不同類型 typescript 也沒有報錯 /.\
什么時候 formControl 才支持類型 . FormControl<T> 不是很好嗎, formContril.value 就有類型可以用 !
11.
ngOutletContext 改成 ngTemplateOutletContext
也支持微語法了.
<ng-template #myTemplate let-value="value" > <div>{{ value }}</div> </ng-template> <ng-template [ngTemplateOutlet]="myTemplate" [ngTemplateOutletContext]="{ value : 'keatkeat' }" ></ng-template> <div *ngTemplateOutlet="myTemplate; context : { value : 'keatkeat' }"></div>
12. call resolver when upstream params change
2.x 版本的 router resolver 比較笨
from "/company/1/employer/1" change to "/company/2/employer/1"
children 的 resolve 是不會重跑一次的. 4.0 開始會跑,即使是 parent 的 route 改變了, child 的 resolve 也會重新跑一次. 這才對嘛
13. router CanDeactivate
多了一個 parameter
@Injectable() export class BlockOut implements CanDeactivate<HomeComponent> { canDeactivate( component: HomeComponent, currentRoute: ActivatedRouteSnapshot, currentstate: RouterStateSnapshot, nextState?: RouterStateSnapshot ): Observable<boolean> | Promise<boolean> | boolean { console.log(currentstate.url); // /home console.log(nextState.url); // /about return true; } }
我們依據 next url 來決定要干什么. 哎喲, 不錯哦.
14. SimpleChanges 多了一個 firstChange 熟悉, 早就該有了嘛!
ngOnChanges(changes: SimpleChanges) { let c = changes["value"]; if (c.firstChange) { console.log(c.previousValue); //undefined console.log(c.currentValue); //keatkeat console.log(c.isFirstChange()); //true } else { console.log(c.previousValue); //keatkeat console.log(c.currentValue); //keatkeat2 console.log(c.isFirstChange()); //false } }
15. MetaService
和 Title 類似, 就是讓我們可以動態添加修改 Meta 等等. 我還沒有測試 server side render , 4.0 好像也有一些變化. 希望有時間 ^^
16. NgComponentOutlet
refer : https://github.com/angular/angular/issues/11168
這個功能是不錯,不過我認為 ng 在動態 component 上面還有很多不足夠的地方。 這個連 binding property, event 都沒有,我不打算用, 沒測試了.
17 http params 容易寫了
this.http.get("http://localhost:61547/api/businesses", { params: { time: "2016-01-01T05:15:12.0000000+08:00" } }).subscribe(v => console.log(v));
直接傳入對象就可以了. (不過上面這個 time string convert 出來好像怪怪的... /.\)
18. Renderer2.setStyle
之前是 setElementStyle,

<h1>{{ title | titlecase }}</h1>
titlecase 是說讓第一個字母大寫, "同時讓后面的字母變小寫", uppercase, lowercase 就不用介紹了吧.
21 ActivatedRoute.paramMap and queryParamMap
其實 param 是可以有多個相同 key 的, 比如 ?data=10&data=11
而獲取的資料是 ActivatedRoute.params["data"] = ["10","11"];
ng 為了要更好的區分這個情況而改進了,現在可以使用 ActivatedRoute.paramMap.get("data") or paramMap.getAll("data") 來做single and multiple 區分.