AngularFireとは
- FIrebase と Angular の公式ライブラリ
- AngularJS 向け
- https://github.com/firebase/angularfire
- firebase 管轄
- Angular 向け
- https://github.com/angular/angularfire2
- angular 管轄
- 最新バージョン: 5.0.0-rc.3
特徴
- RxJS による Angular と Firebase 間のデータのリアルタイム同期
- 各種プロバイダの認証状態の監視
- オフラインデータの自動保存
- ngrx フレンドリー
機能
@NgModules で個別にセットアップする
- AngularFirestoreModule
- 【新DB】Cloud Firestore :new:
- Cloud Firestoreは進化したFirebase Realtime Database - Qiita
- AngularFireAuthModule
- 【認証】Firebase Authentication
- AngularFireDatabaseModule
- 【旧DB】Realtime Database
- AngularFireStorageModule
- 【FileStorage】Cloud Storage (Future release)
- AngularFireMessagingModule
- 【Messaging】Cloud Messaging (Future release)
試したこと
- 開発合宿で作ったお勉強アプリを 生Firebase -> AngularFire に置き換える
- ユーザ認証
- データの読み書き
- 簡単な CRUD のデモを作成
AngularFireAuthModule と AngularFireAuthModule を利用。
デモ
認証
CRUD
認証
AngularFireAuth.authState
を参照する
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
// NG: /app の方を呼ばないと正常に動作しない
// import * as firebase from 'firebase';
export class AppComponent {
constructor(
public afAuth: AngularFireAuth,
) {
login() {
this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
// or this.afAuth.auth.signInWithRedirect(new firebase.auth.GoogleAuthProvider());
}
logout() {
this.afAuth.auth.signOut();
}
}
<div *ngIf="afAuth.authState | async; let user; else showLogin">
<img [attr.src]="user?.photoURL">
<span>{{ user.displayName }}!</span>
<button (click)="logout()">Logout</button>
</div>
<ng-template #showLogin>
<button (click)="login()">Login with Google</button>
</ng-template>
オブジェクトデータの表示 / 編集
AngularFireObject 型を使う
interface Info {
appName: string;
update: Date;
}
export class AppComponent {
infoRef: AngularFireObject<Info>;
info$: Observable<Info>;
constructor(
private afDb: AngularFireDatabase
) {
this.infoRef = afDb.object('info');
this.info$ = this.infoRef.valueChanges(); //Observable
}
updateInfo(appName: string) {
this.infoRef.update({
appName: appName,
update: new Date()
});
}
}
<table>
<tr>
<th>appName</th>
<td>{{(info$ | async)?.appName}}</td>
<td><input #editedAppName [value]="(info$ | async)?.appName"/></td>
<td><button (click)="updateInfo(editedAppName.value)">update</button></td>
</tr>
<tr>
<th>update</th>
<td>{{(info$ | async)?.update}}</td>
</tr>
</table>
配列データの表示 / 追加 / 全削除
AngularFireList 型を使う
interface Task {
name: string;
}
export class AppComponent {
tasksRef: AngularFireList<Task>;
tasks$: Observable<AngularFireAction<firebase.database.DataSnapshot>[]>;
constructor(
private afDb: AngularFireDatabase
) {
this.tasksRef = this.afDb.list<Task>('tasks');
this.tasks$ = this.tasksRef.valueChanges();
}
addTask(taskName: string) {
this.tasksRef.push({
name: taskName
});
}
delAllTask() {
this.tasksRef.remove();
}
}
<input #newTaskName />
<button (click)="addTask(newTaskName.value)">add</button>
<button (click)="delAllTask()">all del</button>
<table>
<tr *ngFor="let task of tasks$ | async">
<td>{{task.name}}</td>
</tr>
</table>
配列データの修正 / 削除
- レコードのキーを得る必要がある
- 以前のバージョンでは勝手に $key とかいうのが生えるので型定義側にも反映される必要があったらしい
- angularfire2を使ってTOUR OF HEROESをいじってみた - Qiita
this.tasks$ = this.tasksRef
.snapshotChanges()
.map(changes =>
changes.map(c => ({key: c.payload.key, ...c.payload.val()}))
);
delTask(key: string) {
this.tasksRef.remove(key);
}
saveTask(key: string, taskName: string) {
this.tasksRef.update(key, {
name: taskName
});
}
<table>
<tr *ngFor="let task of tasks$ | async">
<td>{{task.name}}</td>
<td><button (click)="delTask(task.key)">del</button></td>
<td><input #editedTaskName [value]="task.name" /></td>
<td><button (click)="saveTask(task.key, editedTaskName.value)">update</button></td>
</tr>
</table>
AngularFire のメソッドでデータを絞り込む
this.filterTaskName$ = new BehaviorSubject(null);
this.tasks$ = this.filterTaskName$.switchMap(filterTaskName =>
this.afDb.list<Task>('tasks', ref =>
filterTaskName ? ref.orderByChild('name').equalTo(filterTaskName) : ref
)
.snapshotChanges()
.map(changes =>
changes.map(c => ({key: c.payload.key, ...c.payload.val()}))
)
);
filterTask(filterTaskName: string|null) {
this.filterTaskName$.next(filterTaskName);
}
<input #filterText (keyup)="filterTask(filterText.value)" />
フィルター
this.filterTaskName$ = new BehaviorSubject(null);
this.tasks$ = this.filterTaskName$.switchMap(filterTaskName =>
this.tasksRef
.snapshotChanges()
.map(changes => changes
.map(c => ({key: c.payload.key, ...c.payload.val()}))
.filter(item => !filterTaskName || (new RegExp(filterTaskName, 'i')).test(item.name))
)
);
感想
- 良い点
- RxJS ベースになったのでソースがスッキリした
- 型が扱えてうれしい(機能調べるときの補完とか)
- angular-cli と 合わせて使うとかなり手軽にCRUD+認証付きアプリが作れる
- 良くない点
- 日本語情報
- ググるといろいろあるけど微妙に古くなってまんま利用できないのが多い
- 公式ページ
- 情報の所在がわかりづらい
- リファレンスがない
- 型情報とかソースみないと分からないのがあったりする
- 日本語情報