Angular2也有一個給Firebase使用的Library, 必計是自家的服務,有相對的AngularFire也是正常的,

目前AngularFire2只支援Firebase SDK V2版本,V3版本還在路上。所以在firebase所建立的專案必須要由舊介面建立後再轉至新Console介面,才可以使用。

AngularFire2現在支援Firebase SDK V3版本了,設定方式如下

閱讀全文 »

Angular Component 處理styles有三種模式 1. ViewEncapsulation.None: 適用於全部頁面(No Shadow DOM) 2. ViewEncapsulation.Native: 僅套用於Shadow DOM自己本身 3. ViewEncapsulation.Emulated: 預設行為。 會自動將每個component給予一個名稱,讓各compoent裡面的style會各自獨立

先來看第1,2種,看看style會被放在哪一個位置

  1. ViewEncapsulation.None
1
2
3
4
5
6
7
8
9
10
11
@Component({
selector: 'ck-book',
template: require('./book.html'),
styles: [`
h3 {
color: red
}
`],
encapsulation: ViewEncapsulation.None
})
export class CkBookPage {}

2.ViewEncapsulation.Native

1
2
3
4
5
6
7
8
9
10
11
@Component({
selector: 'ck-book',
template: require('./book.html'),
styles: [`
h3 {
color: red
}
`],
encapsulation: ViewEncapsulation.Native
})
export class CkBookPage {}

注意到ViewEncapsulation.Native將ViewEncapsulation.None的和本身定義的Style都包含在Shadow DOM裡面,這表示該Componenet與外面已經分開了. 本身所定義的css樣式不會影響到別人了

  1. ViewEncapsulation.Emulated為預設行為,會自動將每個Component給予一個名稱,然後在產生html時會將各Componet裡 定義的style加上該名稱,讓css不會互相影響
1
2
3
4
5
6
7
8
9
10
@Component({
selector: 'ck-book',
template: require('./book.html'),
styles: [`
h3 {
color: red
}
`],
encapsulation: ViewEncapsulation.Emulated
})
1
2
3
4
5
6
<style>h3[_ngcontent-jfs-3] {
color: red
}</style>
<div _ngcontent-jfs-3 class="clearfix mx-auto col-8">
<h3 _ngcontent-jfs-3>Booking</h3>
....

參考

在Angular2的Form, 可以使用[(ngModel)]的方式或是使用 ngFormModel的方式(如下)。 ngModel就不多描述,用法跟Angular1.x一樣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<form [ngFormModel]="form" (submit)="add($event)">
<div class="col col-4 mr2">
<label class="label">類別</label>
<select class="select" ngControl="category">
<option value="">--選擇--</option>
<option value="類別1">類別1</option>
<option value="類別2">類別2</option>
</select>
<div *ngIf="!category.valid" class="red">
類別 Required
</div>
</div>
<div class="col col-4 mr2">
<label class="label">金額</label>
<input class="input" type="number"
ngControl="amon" />
<div *ngIf="!amon.valid" class="red">
金額 Required
</div>
</div>
<div class="col col-3 mt3">
<button class="btn btn-primary" type="submit" [disabled]="!form.valid">新增</button>
</div>
</form>

js的部分如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Component } from 'angular2/core';
import {FORM_DIRECTIVES, FormBuilder, Validators, ControlGroup, Control} from 'angular2/common';

@Component({
selector: 'ck-book',
directives: [FORM_DIRECTIVES],
template: require('./book.html')
})
export class CkBookPage {
private form: ControlGroup;
private amon: Control;
private category: Control;
private books = [];

constructor(private builder: FormBuilder) {

this.amon = new Control("", Validators.required);
this.category = new Control("", Validators.required);

this.form = builder.group({
category: this.category,
amon: this.amon
});
}

add(event) {
console.log(this.form.value);
let _value = Object.assign({}, this.form.value);
_value.date = new Date();
this.books.push(_value);

event.preventDefault();
}
};

有幾個新東西出現. ngFormModel, ngControl. 這些都包含在FORM_DIRECTIVES裡.

FormBuilder是用來組合東西給ngFormModel用, 是把Control包在一起 builder.group({ … controls}) Control是配合ngControl使用. 初始是 new Control(『default value』, validator, asyncValidator)

這樣的設定方式,可以讓Form上的動作都在javascript裡面設定。單純html的程式碼

小問題(till Verstion Beta15)

  1. input[type=number]空白時,預設的值會變成NaN. 但是這個被判斷是有值得,所以Validator.required是真的. 這個問題在github上有被提出來也被解決了,但是就到目前為止,修正未包含在裡面. 所以必須手動修改程式碼, 修改方式如下 修改檔案 檔案位置: angular2\src\common\forms\directives\number_value_accessor.js
1
2
3
4
5
6
7
NumberValueAccessor.prototype.registerOnChange = function (fn) {
this.onChange = function (value) { fn(lang_1.NumberWrapper.parseFloat(value)); };
};
change to
NumberValueAccessor.prototype.registerOnChange = function (fn) {
this.onChange = function (value) { fn(value == '' ? null : lang_1.NumberWrapper.parseFloat(value)); };
};

Github commit log

  1. date format設定. 原本 book.date | date:"yyyy-MM-dd"這樣子的寫法輸出的結果會是 2016-04-20. 但是現在的版本locale是被寫死的(en-US), 所以也是要進程式碼手動修改. 檔案位置: angular2\src\common\pipes
1
2
// var defaultLocale = 'en-US'; 修改這裡。參數可以參考moment.js網站
var defaultLocale = 'zh-TW';

參考文章

Angular2的預設route模式是html5,這個在跑到其他頁面後,在重新整理頁面後會出現空白頁面,這是因為找不到Index的入口了。所以解決方式就是要讓MVC Core可以每次都載入Index.html頁面(如果純靜態頁面的方式)

在startup.cs的Configure function, 加入以下程式碼

1
2
3
4
5
6
7
8
9
10
11
app.Use(async (context, next) =>
{
// 判斷request如果不是api call時,則要讀取index.html
if (!Path.HasExtension(context.Request.Path.Value)
&& context.Request.HttpContext.Request.Headers["X-Custom-Header"] != "api"
&& context.Request.HttpContext.Request.Headers["X-Requested-With"] != "XMLHttpRequest")
{
await context.Response.WriteAsync(System.IO.File.ReadAllText("index.html"));
}
await next();
});

在Angular2的index.ts裡設定讓所有的request的header都新增 X-Custom-Header=api,讓server判斷是否為api call

1
2
3
4
5
6
7
8
9
10
11
import { HTTP_PROVIDERS, BaseRequestOptions, RequestOptions, Headers } from 'angular2/http';

class requestOption extends BaseRequestOptions {
headers: Headers = new Headers({ 'X-Custom-Header': 'api' });
}


bootstrap(CkDemoApp, [
...
provide(RequestOptions, { useClass: requestOption })
]);

這樣子就可以讓Angular2跑到不同頁面時,不會因為重新整理而出現空白的畫面

如果是用Controller/View的方式,設定方法比照舊的設定方式即可

Redux2的middleware是介於action和reducer之間。例如: ReduxThunk. 設定方式是在建立store時,將middleware指定給store即可

寫自訂的middleware基本架構如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import isPromise from '../utils/is-promise';

export default function promiseMiddleware({ dispatch }) {
return next => action => {
if (!isPromise(action.payload)) {
return next(action);
}

const { types, payload, meta } = action;
const { promise, data } = payload;
const [PENDING, FULFILLED, REJECTED] = types;

/**
* Dispatch the pending action
*/
let pendingAction = { type: PENDING, payload: null, meta: null };
if (_.isEmpty(data)) {
pendingAction.payload = data;
}
if (_.isEmpty(meta)) {
pendingAction.meta = meta;
}
dispatch(pendingAction);


/**
* If successful, dispatch the fulfilled action, otherwise dispatch
* rejected action.
*/
return promise.then(
result => {
dispatch({
type: FULFILLED,
payload: result,
meta,
});
},
error => {
dispatch({
type: REJECTED,
payload: error,
meta,
});
}
);
};
}

store的設定方式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function configureStore(initialState) {
const store = compose(
_getMiddleware()
)(createStore)(rootReducer, initialState);

return store;
}

function _getMiddleware() {
// 這裡加入middleware
let middleware = [
promiseMiddleware,
ReduxThunk
];

if (__DEV__) {
middleware = [...middleware];
}

return applyMiddleware(...middleware);
}

參考文件: - middleware - redux-thunk