【NCMB】ファイルストアを使ってみよう（後編） with Monaca

# はじめに

本チュートリアルを実践するとこんなアプリが作れます：
<img alt="image_001.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112032/b35b7233-0034-4f2a-e9b3-733eaf1f285e.png" width="250px">

カメラで撮影した画像をサーバー（mobile backend）にアップロード＆データベースで管理するサンプルアプリ。前半でファイル及び情報の保存まで行いましたので、本後半では保存したデータを取得して画面に表示ます。

* 所要時間目安： 動作確認するだけなら10分～15分程度

前編はこちらをご覧ください↓
[【NCMB】ファイルストアを使ってみよう（前編） with Monaca \- Qiita](https://qiita.com/natsumo/items/7e5b02e40bf954e374cc)

# 動作環境

前編と同様です。以下を参照してください。
https://qiita.com/natsumo/items/7e5b02e40bf954e374cc#動作環境
ただし、後編の動作確認はデバッガーアプリがなくてもOKです。PCのプレビュー画面で動作確認ができます。
なお、本後編は[前編](https://qiita.com/natsumo/items/7e5b02e40bf954e374cc)の実装が完了している前提です。

# 作業手順

次の２段回に分けてアプリを作成していきます。

1. [写真の情報を取得して一覧表示する（データストアからの取得）](/natsumo/items/5f5425ea3fcd62331cb4#1-写真の情報を取得して一覧表示するデータストアからの取得)
2. [詳細画面で該当画像を表示する（ファイルストアからの取得）](/natsumo/items/5f5425ea3fcd62331cb4#2-詳細画面で該当画像を表示するファイルストアからの取得)

## 1. 写真の情報を取得して一覧表示する（データストアからの取得）

### 準備

一覧ページへの遷移ボタンを追加します。

* index.html のbodyタグ内「写真を撮る」ボタンの下に、下記のように「写真を見る」ボタンを追記します

```html:index.html
<div>
    <button onclick="takePicture()">写真を撮る</button>
    <button onclick="loadPicture()">写真を見る</button>  // ★追加
</div>
```

一覧ページ（list.html）を用意します。

* index.html と同じ階層に list.htmlを作成する
* index.html のscriptタグ内の末尾に以下を追記する

```js:index.html
function loadPicture() {
    window.location.href = "./list.html";
}
```

* index.html と同じ階層に jsフォルダを作成し、その中に app.js ファイルを作成する
* list.html から共通して使用するAPIキーと初期化の以下コードを index.html から app.js に書き替える
   * index.htmlから 削除して app.js に記載する
   * app.js に元から書かれている文字列 `// This is a JavaScript file` は削除してOK

```js:index.html
var applicationKey = "YOUR_APPLICATION_KEY";
var clientKey = "YOUR_CLIENT_KEY";
var ncmb = new NCMB(applicationKey, clientKey);
```
※ `YOUR_APPLICATION_KEY`, `YOUR_CLIENT_KEY` はそれぞれのキーが入力されている状態です。

* APIキーと初期化を利用できるように、index.html, list.htmlそれぞれ下記を既存のscriptタグの上（headタグ内）に追記する

```html:index.html及びlist.html
<script src="js/app.js"></script> // ★追記
<script>
    // 省略
</script>
```

list.html に「戻る」ボタンを設置します。

* bodyタグ内に以下を記述する
   * 文字列 `This is a template for Monaca app.` は削除してOK

```html:list.html
<button onclick="backpage()">戻る</button>
```

* scriptタグ内に以下を記述する
   * 文字列（3行）`//`, `// TODO: Write JavaScript code here`, `//` は削除してOK

```js:list.html
function backpage() {
    window.location.href = "./index.html";
}
```

#### 動作確認

右側に表示されているプレビュー画面で確認します（もし、プレビュー画面が非表示の場合は、「実行」＞「プレビュータブを表示」をクリックすると表示されます）。

* 「写真を見る」ボタンをクリックすると一覧ページ（「戻る」ボタンのみ）に遷移する
* 「戻る」ボタンをクリックすると元の画面に戻る

### 画面（HTML）の実装

一覧ページが表示されるタイミングでにサーバー（mobile backend）に格納した写真の情報をデータストアから取得して表示するようにします。一覧ページ表示時に関数 `loadPage()` を読み込み込みます。

* list.html の bodyタグに以下のようにonload属性を追記する

```html:list.html
<body onload="loadPage()"> // ★ここ
    <button onclick="backpage()">戻る</button>
</body>
```

取得した写真の情報の表示するリスト（dlタグ）を用意します。

* index.html の bodyタグ内末尾に以下を追記する

```html:list.html
<dl id="photoList" style="max-height: 400px;"></dl> 
```

### 処理（JavaScript）の実装

関数 `loadPage()` を実装します。

* index.html の jsタグ内末尾に以下を追記する

```js:list.html
function loadPage() {
    var FileData = ncmb.DataStore("FileData");
    FileData.fetchAll()
        .then(function(results){
            for (var i = 0; i < results.length; i++) {
                // リストに表示
                var object = results[i];
                
                var title = document.createElement("dt");
                title.innerHTML = object.get("title");
                
                var comment = document.createElement("dd");
                comment.innerHTML = object.get("comment");

                // ★2.でコードを追加します
                
                document.getElementById("photoList").appendChild(title);
                document.getElementById("photoList").appendChild(comment);
            }
        })
        .catch(function(err){
            console.log(err);
        });
}
```

#### コード解説

mobile backend のデータストアから写真の情報を全件取得：

```js
 var FileData = ncmb.DataStore("FileData");
FileData.fetchAll()
    .then(function(results){
        // 取得成功
    })
    .catch(function(err){
        // 取得失敗
    });
```

### 動作確認

右側に表示されているプレビュー画面で確認します（もし、プレビュー画面が非表示の場合は、「実行」＞「プレビュータブを表示」をクリックすると表示されます）。

* 「写真を見る」ボタンをクリックする

少しすると一覧画面にサーバーに格納している写真のタイトルと説明がリスト表示されます（定義リスト形式）。

<img alt="image_002.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112032/4aebfc04-c350-5f06-7375-283d1dfd8a05.png" width="300px">

※上記画像の場合は、「写真を撮る」ボタンから写真を2種類登録してある状況で確認しています。リストを増やすには、デバッガーアプリから動作確認をして、再度写真を追加してから一覧ページを確認してみましょう。表示が増えることが確認できます。
※簡単のためCSSは省略しています。境界線など見づらい場合はご自身でカスタマイズしてください。

## 2. 詳細画面で該当画像を表示する（ファイルストアからの取得）

現時点では写真の情報のみ表示されていますが、ここにボタンを追加し、クリックするとサーバーに保存された画像がダウンロードされて確認できる状態にします。

### 画面（HTML）の実装

画像を表示する場所（imgタグ）を用意します。

* list.html の bodyタグ内に `// ★` の3行をを追記する

```html:list.html
<body onload="loadPage()">
    <button onclick="backpage()">戻る</button>
    <div>                                                                        // ★
        <img id="loadPhoto" src="" style="max-width: 80%; max-height: 400px;">   // ★
    </div>                                                                       // ★
    <dl id="photoList" style="max-height: 400px;"></dl> 
</body>
```

ここに各写真の画像を表示するためのボタンを用意します。ボタンはリストの項目に応じて動的に用意する必要があるため、JavaScriptで実装します。（次の節へ）

### 処理（JavaScript）の実装

写真のタイトルと説明のリスト生成時に「写真を見る」ボタンを各項目に作成します。

* list.html の scriptタグ内、 `// ★2.でコードを追加します` の下に以下を追記する

```jsl:list.html
var btn = document.createElement("button");
btn.innerHTML = "写真を見る";
var fileName = object.get("fileName");
btn.onclick = downloadFile(fileName);
document.getElementById("photoList").appendChild(btn);
```

「写真を見る」ボタンがクリックされると、関数 `downloadFile(fileName)` が呼び出されるようにしています。関数 `downloadFile(fileName)` は引数としてファイル名を受け取り、ファイルデータをダウンロードし表示する処理を実装します。
ファイルを表示するためのメソッド `FileReader()` の起動処理と合わせて実装します。

* list.html の scriptタグ内末尾に以下を追記する

```jsl:list.html
// ファイルリーダーの起動
var reader = new FileReader();
reader.onload = function() {
    var dataUrl = reader.result;
    document.getElementById("loadPhoto").src = dataUrl;
}

function downloadFile(fileName) {
    return function() {              
        // Blob形式で画像データを取得
        ncmb.File.download(fileName, "blob")
            .then(function(blob) {
                // ファイルリーダーにデータを渡す
                reader.readAsDataURL(blob);
            })
            .catch(function(error) {
                alert(error);
            })

    }
}
```

#### コード解説

画像データをフィルストアから取得するときは、保存するときと同様にBlob形式で取得します。

画像ファイルのダウンロード：

```js
// Blob形式で画像データを取得
ncmb.File.download(fileName, "blob")
    .then(function(blob) {
        // ダウンロード成功
        
    })
    .catch(function(error) {
        // ダウンロード失敗
    })
```

### 動作確認

右側に表示されているプレビュー画面で確認します（もし、プレビュー画面が非表示の場合は、「実行」＞「プレビュータブを表示」をクリックすると表示されます）。

* 「写真を見る」ボタンをクリックする

少しすると、先程と同様に写真のタイトルと説明がリスト表示され、その上にそれぞれ「写真を見る」ボタンが表示されます。

<img alt="image_003.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112032/92c81848-766e-5a48-4333-f72d0695ddef.png" width="300px">

* いずれかの「写真を見る」ボタンをクリックする

少し待つとリストの上にクリックした項目に該当する画像がダウンロードされ画面に表示されます。他の「写真を見る」ボタンをクリックすると画像が変わります。

<img alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112032/4de0e4bb-908d-2c8e-c024-c465ede484c1.png" width="250px">

デバッガーアプリから動作確認を行い、登録画像を増やして再度試してみましょう。

# おわりに

前編後編を通して、ファイルストアへの画像アップロード方法とダウンロード方法が習得できたと思います。また、mobile backend サーバーでファイルを管理するときはデータストアとセットで利用することも理解できたと思います。
ぜひ、皆様のアプリ開発に mobile backend のファイルストアを活用してください！

## 補足情報

本チュートリアルではスマートフォンで撮影した画像をリサイズすることなくそのまま保存しています。容量の大きい画像になるとストレージ容量が逼迫したり、アップロードやダウンロードに時間を要したりしますので、用途に合わせてリサイズしてアップロードすると良いです。