Angular入門 未経験から1ヶ月でサービス作れるようにする その12. Firebaseを使ったAPI通信3

## 記事
AngularのHTTP通信のやり方を解説していきます。
FirebaseのAPIを使ってデータの更新、削除をやってみましょう。

## 前回の振り返り
[前回](https://qiita.com/seteen/items/6c09a3e342201c6354af)は、AngularでFirebaseを用いてデータを差k末井する方法を学びました。
本記事は、Firebase周りの記事の 3記事目となりますので、過去記事の内容を頭に入れておいてください。
わからなくなったら、その1から再度やり直してみましょう。

## この記事のソースコード
[https://github.com/seteen/AngularGuides/tree/入門その12](https://github.com/yazumoto/AngularGuides/tree/%E5%85%A5%E9%96%80%E3%81%9D%E3%81%AE12)


## Firebaseを使うようにしたことによっておかしくなっている変更部分を修正する

### 画面表示の修正

Firebaseを利用する前は、コード上に記載した `Product` のデータを利用して画面表示を行っていました。
その際には ID を 1から振っていましたが、 Firebase を利用することで、それが文字列の key に変更されました。
まずはその部分に対応します。

```src/app/product/product-list/product-list.component.html
... 略
        <div class="product-line header">
          <div class="product-id">KEY</div> // <= KEY に変更
          <div class="product-name">名前</div>
          <div class="product-price">価格</div>
        </div>
        <div class="product-line" *ngFor="let product of products" (mouseenter)="hovered(product)" (mouseleave)="unhovered(product)">
          <div class="product-id">{{ product.key }} </div> // <= product.key に変更 
          <div class="product-name">{{ product.name }}</div>
          <div class="product-price">
            <span *ngIf="!product.hovered; else Unhovered">{{ product.price }}</span>
            <ng-template #Unhovered><span class="button white" [routerLink]="[product.key]">詳細</span></ng-template> // <= routerLink を product.key に変更
          </div>
        </div>
... 略
```

上記に伴って、少しCSSを変更しました。

![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67424/cf5d1df8-ebce-9357-3eae-2d913ea89d8e.png)

上記は商品一覧画面ですが、商品詳細画面、商品編集画面も同じように修正しています。

#### ここまでのコミット

https://github.com/yazumoto/AngularGuides/commit/16bc8396bc2c4adf8eacaa31cf341f2c1d9241a4

### データ取得部分の修正

現状では、商品詳細画面、商品編集画面では ID を基にコード上に定義したデータを検索するようにしているため、Firebaseを利用するように修正します。


```src/app/shared/services/product.service.ts
... 略
  get(key: string): Observable<Product> { // <= get(id: number) を修正
    return this.http.get(`${this.BASE_URL}/users/${this.UID}/products/${key}.json`, { params: { auth: this.TOKEN } }).pipe(
      map((response: any) => {
        return new Product(key, response.name, response.price, response.description);
      })
    );
  }
... 略
```

これにより、商品詳細、商品編集画面のデータがちゃんと表示されるようになりました。

### その他の小さな修正

前回商品作成画面にてデータを作成するようにしたのですが、作成後に特に画面遷移を行うようにしていなかったため、商品一覧画面に遷移するようにします。

```src/app/product/product-new/product-new.component.ts
... 略
  saveProduct(): void {
    if (this.productForm.valid) {
      const { name, price, description } = this.productForm.getRawValue();
      this.productService.create(new Product(null, name, price, description)).subscribe(() => {
        this.router.navigate(['/products']); // <= ここを追加
      });
    }
  }
... 略
```

#### ここまでのコミット

商品作成後の遷移↓
https://github.com/yazumoto/AngularGuides/commit/5e4e38ea981845a0e9f50b2abaf3bb0e0272792a

データ取得部分の修正↓
https://github.com/yazumoto/AngularGuides/commit/173c863bc60da891540186ad506bfd7712444716

### Firebaseを使ったデータの更新

次に、データの更新部分をFirebaseに対応させます。

まずは、 `ProductService` を更新します。

```src/app/shared/services/product.service.ts
... 略
  update(product: Product): Observable<void> {
    return this.http.patch(`${this.BASE_URL}/users/${this.UID}/products/${product.key}.json`, {
      name: product.name,
      price: product.price,
      description: product.description
    }, { params: { auth: this.TOKEN } }).pipe(
      map(() => {})
    );
  }
... 略
```

 `http` の `PATCH` メソッドを使うことで、データの更新ができるようになりました。
 FirebaseのAPIはわかりやすくて良いですね。


呼び出し元も修正しましょう。

```src/app/product/product-edit/product-edit.component.ts
... 略
  saveProduct(): void {
    if (this.productForm.valid) {
      const { key, name, price, description } = this.productForm.getRawValue();
      this.productService.update(new Product(key, name, price, description)).subscribe(() => {
        this.router.navigate(['/products', this.productForm.controls.key.value]);
      });
    }
  }
... 略
```

これで編集画面がちゃんと動作します。

#### ここまでのコミット

https://github.com/yazumoto/AngularGuides/commit/a3a5ef1252ef8e82f4b86a4567231809214ca68c

### Firebaseを使ったデータの削除

最後に、商品の削除を実装していきます。

削除も他のAPIとほとんどやることは同じです。
`http` の `DELETE` メソッドを利用します。

#### ProductService への削除メソッドの実装

``` src/app/shared/services/product.service.ts
... 略
  delete(key: string): Observable<void> {  // <= メソッドを追加
    return this.http.delete(`${this.BASE_URL}/users/${this.UID}/products/${key}.json`, { params: { auth: this.TOKEN }}).pipe(
      map(() => {})
    );
  }
... 略
```

ほとんど更新のときと同じです。

 
#### 削除ボタンの実装
 
現状では削除ボタンがありませんので、削除ボタンを実装していきます。
 
```src/styles.scss
.button {
  ... 略

  &.red {
    background-color: #F44336;
  }
}
```

削除風のボタンがなかったため、グローバルなCSSに赤いボタンを追加しておきます。

次に、編集画面に削除ボタンを追加します。

```src/app/product/product-edit/product-edit.component.html
... 略
    <div class="footer">
      <span class="button white" [routerLink]="['/products', productForm.controls.key.value]">キャンセル</span>
      <button class="button black" [class.disabled]="productForm.invalid">保存</button>
      <span class="button red" (click)="deleteProduct()">削除</span> // <= 追加
    </div>
... 略
```

`button` にすると 押したときに `submit` イベントが発生してしまうので、キャンセルボタンと同じように `span` で作りました。

最後に、上記HTMLで呼ばれている `deleteProduct()` メソッドを追加します。

```src/app/product/product-edit/product-edit.component.ts
... 略
  deleteProduct(): void { // <= メソッドを追加
    if (window.confirm('本当に削除しますか？')) {
      this.productService.delete(this.productForm.controls.key.value).subscribe(() => {
        this.router.navigate(['/products']);
      });
    }
  }
... 略
```

削除なので、 `本当に削除しますか？` という確認を行ってから削除するようにしました。


#### 動作確認

データの更新、削除の動作を確認してみます。

![002.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67424/0b17ad57-899e-b78c-812f-f8ab6e67976e.gif)

#### ここまでのコミット

https://github.com/yazumoto/AngularGuides/commit/a1cb959faca89464a5d8838791ee4f4be1ef30dc

## まとめ

今回は、AngularでのFirebaseを利用するまとめとして、更新、削除を学びました。
今回で、Firebaseを使った商品の一覧、詳細、作成、編集、削除という要素が全て完成し、サービスを作れる自信がついてきたのではないでしょうか。

次回は、PIPEの使い方を見ていきます。

## 入門記事一覧

「Angular入門 未経験から1ヶ月でサービス作れるようにする」は、記事数が多いため、まとめ記事 を作っています。
https://qiita.com/seteen/items/43908e33e08a39612a07