How to CRUD in Angular + Firebase Firestore

CRUD – Create, Read, Update, Delete – the four holy grail of database actions.データベースアクションの4つの神聖なものです。 これらは、データベースで何か重要なことを行うために必要な唯一のものです。 もちろん、クエリの複雑さを増すことはできますが、結局のところ、これら 4 つのアクションに集約されます。

Firebase は、API フック、ファイル ストレージ スペース、認証システムおよびホスティング機能を備えた、Google が所有するクラウドベースのシステムです。 プロトタイピングや迅速なアプリケーション開発にもっと活用されるべき、過小評価されているシステムです。

プログレッシブ Web アプリを起動したいが、サーバーのセットアップやAPIの作成、データベースの処理といったバックエンドの経験がない場合、Firebase は、アプリを起動して実行するために処理しなければならない大量の情報によって孤立し停滞するフロントエンド開発者にとって素晴らしいオプションになります。

また、時間がない場合、Firebase は開発時間をほぼ半分に短縮し、ユーザー エクスペリエンスと UI フローの実装に集中することができます。 また、必要に応じて、フロントエンド アプリケーションを移行し、別のデータベースを使用するのに十分な柔軟性があります。

これは、注文の追加 (作成)、データベースからの注文の一覧表示 (読み取り)、注文の完了マーク (更新)、注文の削除 (削除) を行う、骨太のコーヒー注文アプリです。

The purpose of this tutorial is to help you get started with Firebase Firestore and see how easy to connect to the Google owned service and get started on ⧏35⧐ =Firebaseが持つサービスを始めるのがいかに簡単か。 これは Google の広告ではなく (この件に関して Google からキックバックを受けていません)、単に Angular がデータベースとどのように連携するかを説明するものです。

これから作成するアプリは完璧ではありません。 データ検証のような不足しているものがあり、私が追加できる可能性のある機能は山ほどあります。 しかし、それは重要ではありません。 ポイントは、できるだけ早く Angular でセットアップし、実際のデータベースで動作させることです。

では、紹介は十分でした。 Angular CLI をまだ持っていない場合は、ここで詳細を確認できます。

要するに、ターミナルで Angular アプリを配置するディレクトリでこれらのコマンドを実行するだけです。

npm install -g @angular/cli

Angular CLI を持っていない場合は、ターミナルにインストールします。

ng new name-of-app-here

Angular の最新バージョンを使用して、新しい Angular プロジェクトを作成します。

ng serve

これは、Angular プロジェクトを起動して実行します。

Setting up Angular

この Angular アプリ用に、合計 3 つの新しいパーツ、orders、order-list、および shared/ordersService を作成するつもりです。 最初の 2 つはアプリのインターフェイスを含むコンポーネントで、shared/orders サービスはすべての Firebase API 呼び出しをまとめて管理します。

必要なファイルを作成するには、次のコマンドを実行します:

ng g c orders

g は generate、c は component を意味します。 コマンドの最後の部分は、ファイルの名前で、上記の場合は orders と呼ばれます。

次のコマンドを使用して、order-list の別のコンポーネントを作成します。 コンポーネントのように自動的に作成されるわけではないので、必ず orders.service.tsapp.module.ts に追加してください。 これは、import を使用して、次のように providers リストに追加することができます。 これは必須ではなく、必要であれば、任意の CSS フレームワークまたは独自のカスタム CSS を使用することができます。 743>

また、Googles のマテリアル アイコンをボタンとして使用して、コーヒーの注文を完了としてマークしたり、注文を削除したりする予定です。

これを実装する 1 つの方法は、src フォルダにある index.html ファイルの </head> タグのすぐ上に以下のコードを持つことです。

<!-- Compiled and minified Materialize CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!-- Compiled and minified Materialize JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script><!-- Google Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />

初期の Angular ビュー コード

app.component.htmlでは、すべてのスターター コードを削除してください。

先ほど作成したコンポーネントにフックし、セレクタapp-ordersapp-order-listを使用して画面に表示します。 これを行うには、以下のコードを記述します。

<div class="container">
<div class="row">
<app-orders class="col s6"></app-orders>
<app-order-list class="col s6"></app-order-list>
</div>
</div>

containerrowcol および s6 クラスは、Materialize CSS グリッド システムの一部分です。 このチュートリアルの残りの部分で見ることになるすべてのクラスは、特に言及しない限り、Materialize CSS のものです。

フォームを設定する

フォームを設定するために、app.module.tsReactiveFormsModuleを、imports配列でそれを忘れずにインポートしてください。

import { ReactiveFormsModule } from "@angular/forms";

内部ではorders.service.ts@angular/formsからFormControlFormGroupをインポートし、constructorの外部で新しいフォームを作成し、以下のようにフォームのプロパティを設定します:

import { FormControl, FormGroup } from "@angular/forms";
...
...export class OrdersService {
constructor() {}
form = new FormGroup({
customerName: new FormControl(''),
orderNumber: new FormControl(''),
coffeeOrder: new FormControl(''),
completed: new FormControl(false)
})
}

これらの値を使用して、このチュートリアルで少し後にFirebaseに保存することにします。

Using the form inside a component

import OrdersService クラスをコンポーネントに組み込み、コンポーネント内でオブジェクトを使用し、constructor内でそのクラスのオブジェクトを作成します。

import { OrdersService } from "../shared/orders.service";
...
constructor(private ordersService:OrdersService){}

orders.component.html 内では formGroup 命令を使って OrdersService で作成したフォームオブジェクトを参照してください。 各formControlNameは、OrdersServiceクラスの内部で作成したformGroupで使用した名前を参照しています。 これにより、関連するコントローラがフォームに入力された変数を使用することができるようになります。

<form ="this.ordersService.form">
<input placeholder="Order Number"
formControlName="orderNumber"
type="text"
class="input-field col s12">
<input placeholder="Customer Name"
formControlName="customerName"
type="text"
class="input-field col s12">
</form>

orders.component.tsでは、orders.component.htmlでループさせるためのコーヒーの配列を設定するつもりです。 理論的には、Firestoreデータベース内でこれを設定し、コレクションを呼び出してから使用することもできます。 しかし、ここでは長さを考慮して、ローカル配列としてセットアップすることにします。 OrdersComponent クラスの内部に、次の配列を設定します。

coffees = ;

orders.component.html<form> タグの内部で、(click) アクション ハンドラを使用して *ngFor を使用してループし、注文に新しいコーヒーを追加します。

<button class="waves-effect waves-light btn col s4" 
*ngFor="let coffee of coffees"
(click)="addCoffee(coffee)">
{{coffee}}
</button><ul class="collection">
<li *ngFor="let coffee of coffeeOrder">
<span class="col s11"> {{ coffee }} </span>
<a class="col s1" (click)="removeCoffee(coffee)">x</a>
</li>
</ul>

orders.component内で、コーヒー注文を格納する空の配列を作成し、関数 addCoffee() を使用して新しいコーヒーを追加し、removeCoffee() を使用して注文リストから飲料を削除します。

coffeeOrder = ;addCoffee = coffee => this.coffeeOrder.push(coffee);removeCoffee = coffee => {
let index = this.coffeeOrder.indexOf(coffee);
if (index > -1) this.coffeeOrder.splice(index, 1);
};

フォーム送信の処理

<form>タグの内部および下部に注文の送信入力を追加し、onSubmit()を次のようなクリック ハンドラに追加します。 この関数には、すぐにイベント処理を追加する予定です。 この時点で、Firebase データベースにフックするためのフォームの準備が整いました。

リストコンポーネントのセットアップ

さて、データベースからのコーヒー注文を表示するスペースが必要なだけです。

自分の order-list.component.html に移動して、3 つの見出しと 5 つのデータ セルを持つテーブルを作成します。 最初の3つのデータセルは、データベースから取得した値を保持し、最後の2つは、注文を完了としてマークしたり、注文を削除したりするための追加機能を保持します。

Setting up Firebase

Firebaseコンソールに移動して新しいプロジェクトを追加します。

プロジェクト名を付け、コントローラ-コントローラの条件を承諾してプロジェクトを作成します。

Firebaseプロジェクトが設定されると、このような画面が表示されるでしょう。

サイドパネル(Developの下にあります)のDatabaseを選択してデータベースを作成し、Cloud Firestoreのバナーの下のCreate Databaseをクリックします。

Create databaseをクリックします

セキュリティルールはテストモードで開始を選択してください。

セキュリティのために、認証情報をローカルマシンにのみ保存することを忘れないでください。

このように空のFirestoreデータベースが表示されます。

Firebase Firestore を Angular に接続する

Angular アプリを Firebase に接続するには、firebase および @angular/fire パッケージをインストールする必要があるでしょう。 これにより、AngularFireModuleAngularFirestoreModuleにアクセスできるようになります。

npm i --save firebase @angular/fire

コネクタの実装

FirebaseのWebコンソールに戻り、Angularアプリで使用する設定詳細を取得します。 これは、Project Overview ページにあります。 次のようになります。

自分のクレデンシャルを使用する必要があります。

コードのハイライト部分をコピーし、environment.ts ファイル (environments フォルダ内にあります) に移動して、environment オブジェクト内に firebaseConfig として設定の詳細を貼り付けます。 例として以下を参照してください:

export const environment = {
production: false,
firebaseConfig: {
apiKey: "xxx",
authDomain: "xxxx.firebaseapp.com",
databaseURL: "https://xxxx.firebaseio.com",
projectId: "xxxx",
storageBucket: "xxxx.appspot.com",
messagingSenderId: "xxxxx"
}
};

先にインストールしたパッケージと environment.ts ファイルを app.module.ts にインポートしてください。 以下の例を参照してください。

import { environment } from "src/environments/environment";
import { AngularFireModule } from "@angular/fire";
import { AngularFirestoreModule } from "@angular/fire/firestore";
...
@NgModule({
...
imports:
...
})

サービスに Firestore を設定する

AngularFirestoreorders.service.ts ファイルにインポートして、コンストラクタで宣言し、サービスがそれを認識できるようにします。

...
import { AngularFirestore } from '@angular/fire/firestore';
...
export class OrdersService {
constructor( private firestore: AngularFirestore ) {}
...
}

これで準備はすべて整いましたので、この Angular + Firebase Firestore チュートリアルの CRUD パートに取り掛かる準備ができました。

C is for Create

真新しい Firestore データベースに新しいレコードを作成するには、.add() を呼び出す必要があるでしょう。 これを orders.service.ts ファイル内で行います。

これを行うには、collection 名と、データベースにプッシュしたいデータを指定する必要があります。 私たちの場合、それは coffeeOrders です。

以下のサンプルコードは、Firebase の呼び出しを返すためにプロミスを使用し、それがすべて終わった後に何をしたいかを決めることができます。

...
createCoffeeOrder(data) {
return new Promise<any>((resolve, reject) =>{
this.firestore
.collection("coffeeOrders")
.add(data)
.then(res => {}, err => reject(err));
});
}
...

コンポーネントでこの関数を呼び出すには、orders.component.ts に移動して、onSubmit() 関数とアクション ハンドラ内で、createCoffeeOrder() から ordersService を呼び出します。

以下の例では、coffeeOrder 配列をフォーム値 coffeeOrder にマッピングしてデータの何らかの処理を行なっています。 また、構造改革のために data 変数を作成しました (createCoffeeOrder() に非常に長い名前を渡す必要がないため).

...
onSubmit() {
this.ordersService.form.value.coffeeOrder = this.coffeeOrder;
let data = this.ordersService.form.value;
this.ordersService.createCoffeeOrder(data)
.then(res => {
/*do something here....
maybe clear the form or give a success message*/
});
}
...

そしてビオラ! これで、ローカル ホストの Angular アプリから Firestore データベースへのレコードが作成されました。

R is for Read

コーヒー注文データを表示するために、orders.service.ts に読み取り関数が必要になります。 次のコード例では、coffeeOrders コレクションに格納されているすべての値を取得できます。

...
getCoffeeOrders() {
return
this.firestore.collection("coffeeOrders").snapshotChanges();
}
...

この関数を使用するには、orders-list.component.ts から呼び出す必要があります。 これを行うには、OrdersService をファイルにインポートし、constructor で初期化します。

...
import { OrdersService } from "../shared/orders.service";
...export class OrderListComponent implements OnInit {
constructor(private ordersService:OrdersService){}
...
}

呼び出しを含む関数を作成し、ngOnInit() で初期化してビューが初めてロードされるときにそれを呼び出します。 データベースから返された結果をsubscribe()経由でマッピングするために、coffeeOrders変数を作成します。 これを使用して、order-list.component.html

...
ngOnInit() {this.getCoffeeOrders();}
... coffeeOrders; getCoffeeOrders = () =>
this.ordersService
.getCoffeeOrders()
.subscribe(res =>(this.coffeeOrders = res));...

で反復処理と表示を行います。order-list.component.htmlcoffeeOrders を使用するには、*ngFor を使用して返された配列をループ処理します。 また、各顧客のコーヒーのリストを取得するために、少しインセプションを行い、coffeeOrder部分について別のループを行う必要があります。 これを行うにはより効率的な方法がありますが、このチュートリアルでは、以下のサンプル コードを参照してください:

...
<tbody>
<tr *ngFor="let order of coffeeOrders">
<td>{{ order.payload.doc.data().orderNumber }}</td>
<td>{{ order.payload.doc.data().customerName }}</td>
<td><span
*ngFor="let coffee of order.payload.doc.data().coffeeOrder">
{{ coffee }}
</span>
</td>
</tr>
</tbody>
...

そして、これで完了です。

U is for Update

データベースでコーヒー注文を完了としてマークし、その変更に基づいて行項目に何かをすることができるとします。 snapshot() は発生したすべての変更を追跡するので、データベースへの追跡やポーリングは必要ありません。

Google Materialize Icons の「チェック」アイコンを使用してテーブル内に別のデータ セルを作成し、(click) イベントに接続して、order-list.component.ts の関数 markCompleted() を呼び出すことにします。

データ セルに 属性と completed 値を設定し、「チェック」アイコンが表示されるかどうかを動的に判断できるようにする予定です。 この値は、最初に orders.service.ts .

...
<td ="order.payload.doc.data().completed"
(click)="markCompleted(order)">
<i class="material-icons">check</i>
</td>
...

Inside order-list.component.ts でフォームを作成したときに false として設定しました。注入された data を使用して、orders.service.ts.

...
markCompleted = data =>
this.ordersService.updateCoffeeOrder(data);
...

Inside orders.service.tsupdateCoffeeOrder() という関数に渡す関数 markCompleted() を作成して、処理する関数を作成します。 この関数は、選択されたコレクションとドキュメントIDに基づいてFirestoreデータベースを接続し、呼び出します。 私たちのコレクションが coffeeOrders という名前であることはすでに知っており、コンポーネント関数呼び出しから渡されたパラメータに基づいてドキュメント ID を見つけることができます。

.set() は、あなたが渡したどんなデータでも特定のレコードに設定します。 .set() は 2 つのパラメータを受け取ります – データと設定オブジェクトです。 merge: true を使用する場合、ドキュメント全体を渡したもので置き換えるのではなく、渡された値とキーのペアを更新するだけであることを意味します。

...
updateCoffeeOrder(data) {
return
this.firestore
.collection("coffeeOrders")
.doc(data.payload.doc.id)
.set({ completed: true }, { merge: true });
}
...

これで、ビューで「チェック」アイコンをクリックすると、 属性が true に設定されているため、データベースが更新されて消えます。

D is for Delete

最後のアクションでは、更新プロセスと同様の方法ですべてを設定しますが、レコードを更新するのではなく、削除することにします。 delete_forever」アイコンがクリックされたときに、ループ内の order データのインスタンスを渡すつもりです。 これはドキュメントIDのために必要です。

...
<td ="order.payload.doc.data().completed"
(click)="deleteOrder(order)">
<i class="material-icons">delete_forever</i>
</td>
...

あなたの order-list.component.ts の内部で、あなたの orders.service.ts の内部の deleteCoffeeOrder() 関数を呼び出す関連関数を作成します。 .

...
deleteOrder = data => this.ordersService.deleteCoffeeOrder(data);
...

あなたの orders.service.ts ファイルの内部で、deleteCoffeeOrder() 関数を作成して、ドキュメント ID が何かを把握するために注入した data を使用してください。 update と同様に、削除したいレコードを正しく識別するために、コレクション名とドキュメント ID の両方を知る必要があります。

...
deleteCoffeeOrder(data) {
return
this.firestore
.collection("coffeeOrders")
.doc(data.payload.doc.id)
.delete();
}
...

ここで「delete_forever」アイコンをクリックすると、Angularアプリが起動し、特定のレコードを削除するようにFirestoreに指示します。

Final Application

作業プロジェクト全体の Github リポジトリは、ここで見つけることができます。 Firebaseのデータベースを自分で作成し、設定ファイルを更新して自分でフックアップする必要があります。 コード自体は完璧ではありませんが、コードのジャングルを進むことなく、Angular アプリで Firestore がどのように動作するかを確認できるように、非常に最小限に抑えてあります。

詳細を見逃すことなく、できるだけチュートリアルを凝縮するよう努めました。 難しい組み合わせでしたが、上で見たように、多くはほとんど Angular のコードであり、Firestore はあまりありません。 Firebase Firestoreはもっと複雑なクエリを実行できますが、デモのためにシンプルにしています。 理論的には、データ構造が同じであれば、Firestore を交換し、必要なリファクタリングを最小限に抑えて異なる API 接続のセットを置くことができます。

最後に

個人的には、バックエンド全体とそれをサポートするサーバーを作成する必要なく、プロダクション準備プロジェクトをすばやく作成できる点でFirebaseが気に入っています。 コスト面でも悪くなく、テストプロジェクトは無料で起動できます(しかも、プランを切り替えるまでクレジットカードの詳細を入力させることはありません)。 全体として、アプリケーションをFirestoreに接続する実際の行為よりも、フォームとアプリケーションを取り巻くインタフェースを作成する方が時間がかかりました。 長くなるので、このチュートリアルにはフォームの検証を追加していませんが、将来的には別の記事を作成する予定です

コメントする