kintone プラグイン開発メモ　その７（設定画面にkintoneアプリのフィールドを取得して表示させる）

プラグインには、アプリの情報を利用するものとしないものがあります。
今回作成するプラグインは、kintoneアプリのフィールド情報を取得して、取得したフィールド情報を元に設定画面にフィールドを生成していきたいと思います。

# 数値フィールドゼロ埋めプラグイン
計算フィールドの結果が#N/A!となって計算ができないことがあります。
https://jp.cybozu.help/k/ja/user/app_settings/form/autocalc/autocalc_error.html
初期値に0を入れておくなど対応ができるケースもありますが、諸事情により難しい場合もあります。
計算に使う元の数値フィールドをゼロ埋めするプラグインを作っていきたいと思います。

# 開発環境

 - MacBook Pro
 - macOS 10.13.6 (17G65)
 - Darwin 17.7.0
 - Google Chrome バージョン: 71.0.3578.98

# プラグイン作成までの概要
大きく次のような流れで作成してみます。

 1. アプリの作成
 2. アプリ側のJavaScriptカスタマイズの作成
 3. プラグイン設定画面の作成
 4. プラグイン設定画面のJavaScriptの作成

# アプリの作成
テストアプリを作っていきます。
アプリの追加から、はじめから作成を選んで次のようなフィールドを追加します。

| フィールド名 | フィールドタイプ | フィールドコード |
|:-----------------|:------------------:|:------------------:|
| 品番_ルックアップ  | SINGLE_LINE_TEXT | 品番_ルックアップ  |
| 商品名 | SINGLE_LINE_TEXT | 商品名 |
| 数量 | NUMBER | 数量 |
| 単価 | NUMBER | 単価 |
| 計算 | CALC | 計算 |
| 品番\_ルックアップ_0  | SINGLE_LINE_TEXT | 品番\_ルックアップ_0  |
| 商品名_0 | SINGLE_LINE_TEXT | 商品名_0 |
| 数量_0 | NUMBER | 数量_0 |
| 単価_0 | NUMBER | 単価_0 |
| 計算_0 | CALC | 計算_0 |
| 品番\_ルックアップ_1  | SINGLE_LINE_TEXT | 品番\_ルックアップ_1 |
| 商品名_1 | SINGLE_LINE_TEXT | 商品名_1 |
| 数量_1 | NUMBER | 数量_1 |
| 単価_1 | NUMBER | 単価_1 |
| 計算_1 | CALC | 計算_1 |
| 合計 | CALC | 合計 |

<img width="1233" alt="スクリーンショット 2019-01-27 9.05.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/214523/e202741f-17cf-7028-8e92-49eb6b0c688b.png">

商品を３点まで入力できるフォームを作成しました。３点全てを入力する場合は問題ありませんが、２点しか入力しなかった場合は、計算フィールドが#N/A!となり計算されません。
下の例の場合は、単価_1に0を入力して計算結果が表示されるようにしたいと思います。
<img width="950" alt="スクリーンショット 2019-01-27 9.04.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/214523/3f1be7da-1ce2-9aec-1d10-c825420f0311.png">

# 開発環境の準備
次のようなディレクトリとファイルを作ります。

```sh
$ mkdir zero-fill
$ cd zero-fill
$ mkdir src
$ cd src
$ mkdir html
$ mkdir image
$ mkdir js
$ touch ./html/config.html
$ touch ./html/config.js
$ touch ./js/customize.js
$ touch manifest.json
$ cd ..
$ tree .
.
└── src
    ├── html
    │   ├── config.html
    │   └── config.js
    ├── image
    ├── js
    │   └── customize.js
    └── manifest.json
```

# アイコンファイル作成
アイコンファイルを作成します。ファイルのサイズに注意が必要です。
参考：[kintone プラグイン開発手順]
適当なアイコンを作成します。
![icon.png](https://qiita-image-store.s3.amazonaws.com/0/214523/ccceb78c-be01-a612-43ac-00765782dc10.png)

# アプリのフィールドレイアウト、フィールド情報の取得のテスト
アプリのフィールド情報を取得するには、kintoneAPIを利用します。
アプリ画面を開いた状態で、Chromeデベロッパーツールを開いてコンソールでAPIを叩いて情報を表示してみます。

### フォームレイアウト情報の取得
https://developer.cybozu.io/hc/ja/articles/204783170#anchor_getform_layout

```javascript
var body = {
    "app": appId
};
kintone.api(kintone.api.url('/k/v1/app/form/layout', true), 'GET', body, function(resp) {
    // success
    console.log(resp);
}, function(error) {
    // error
    console.log(error);
});
```
```json
layout: Array(4)
0:
fields: Array(5)
0: {type: "SINGLE_LINE_TEXT", code: "品番_ルックアップ", size: {…}}
1: {type: "SINGLE_LINE_TEXT", code: "商品名", size: {…}}
2: {type: "NUMBER", code: "数量", size: {…}}
3: {type: "NUMBER", code: "単価", size: {…}}
4: {type: "CALC", code: "計算", size: {…}}
length: 5
__proto__: Array(0)
type: "ROW"
__proto__: Object
1:
fields: Array(5)
0: {type: "SINGLE_LINE_TEXT", code: "品番_ルックアップ_0", size: {…}}
1: {type: "SINGLE_LINE_TEXT", code: "商品名_0", size: {…}}
2: {type: "NUMBER", code: "数量_0", size: {…}}
3: {type: "NUMBER", code: "単価_0", size: {…}}
4: {type: "CALC", code: "計算_0", size: {…}}
length: 5
__proto__: Array(0)
type: "ROW"
__proto__: Object
2:
fields: Array(5)
0: {type: "SINGLE_LINE_TEXT", code: "品番_ルックアップ_1", size: {…}}
1: {type: "SINGLE_LINE_TEXT", code: "商品名_1", size: {…}}
2: {type: "NUMBER", code: "数量_1", size: {…}}
3: {type: "NUMBER", code: "単価_1", size: {…}}
4: {type: "CALC", code: "計算_1", size: {…}}
length: 5
__proto__: Array(0)
type: "ROW"
__proto__: Object
3:
fields: Array(2)
0: {type: "LABEL", label: "<div><div style="text-align:right">合計</div></div>", size: {…}}
1: {type: "CALC", code: "合計", size: {…}}
length: 2
__proto__: Array(0)
type: "ROW"
__proto__: Object
length: 4
__proto__: Array(0)
revision: "14"
```

### フォームフィールド情報の取得
https://developer.cybozu.io/hc/ja/articles/204783170#anchor_getform_fields

```javascript
var body = {
    "app": appId
};

kintone.api(kintone.api.url('/k/v1/app/form/fields', true), 'GET', body, function(resp) {
    // success
    console.log(resp);
}, function(error) {
    // error
    console.log(error);
});
```

```json
properties:
カテゴリー: {type: "CATEGORY", code: "カテゴリー", label: "カテゴリー", enabled: false}
ステータス: {type: "STATUS", code: "ステータス", label: "ステータス", enabled: false}
レコード番号: {type: "RECORD_NUMBER", code: "レコード番号", label: "レコード番号", noLabel: false}
作成日時: {type: "CREATED_TIME", code: "作成日時", label: "作成日時", noLabel: false}
作成者: {type: "CREATOR", code: "作成者", label: "作成者", noLabel: false}
作業者: {type: "STATUS_ASSIGNEE", code: "作業者", label: "作業者", enabled: false}
単価: {type: "NUMBER", code: "単価", label: "単価", noLabel: false, required: false, …}
単価_0: {type: "NUMBER", code: "単価_0", label: "単価_0", noLabel: false, required: false, …}
単価_1: {type: "NUMBER", code: "単価_1", label: "単価_1", noLabel: false, required: false, …}
合計: {type: "CALC", code: "合計", label: "合計", noLabel: true, required: false, …}
品番_ルックアップ: {type: "SINGLE_LINE_TEXT", code: "品番_ルックアップ", label: "品番_ルックアップ", noLabel: false, required: false, …}
品番_ルックアップ_0: {type: "SINGLE_LINE_TEXT", code: "品番_ルックアップ_0", label: "品番_ルックアップ_0", noLabel: false, required: false, …}
品番_ルックアップ_1: {type: "SINGLE_LINE_TEXT", code: "品番_ルックアップ_1", label: "品番_ルックアップ_1", noLabel: false, required: false, …}
商品名: {type: "SINGLE_LINE_TEXT", code: "商品名", label: "商品名", noLabel: false, required: false, …}
商品名_0: {type: "SINGLE_LINE_TEXT", code: "商品名_0", label: "商品名_0", noLabel: false, required: false, …}
商品名_1: {type: "SINGLE_LINE_TEXT", code: "商品名_1", label: "商品名_1", noLabel: false, required: false, …}
数量: {type: "NUMBER", code: "数量", label: "数量", noLabel: false, required: false, …}
数量_0: {type: "NUMBER", code: "数量_0", label: "数量_0", noLabel: false, required: false, …}
数量_1: {type: "NUMBER", code: "数量_1", label: "数量_1", noLabel: false, required: false, …}
更新日時: {type: "UPDATED_TIME", code: "更新日時", label: "更新日時", noLabel: false}
更新者: {type: "MODIFIER", code: "更新者", label: "更新者", noLabel: false}
計算: {type: "CALC", code: "計算", label: "計算", noLabel: false, required: false, …}
計算_0: {type: "CALC", code: "計算_0", label: "計算_0", noLabel: false, required: false, …}
計算_1: {type: "CALC", code: "計算_1", label: "計算_1", noLabel: false, required: false, …}
__proto__: Object
revision: "14"
```

# 設定画面モックアップ
設定画面を動的に生成しますが、その前に生成後の画面を作ってみたいと思います。

<img width="329" alt="スクリーンショット 2019-01-27 21.32.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/214523/18e98824-6ebb-cd0a-3086-6578d139074e.png">

```config.html
<html>
    <body>
        <h1>ゼロ埋めプラグイン設定画面</h1>
        <div id="form">
            <div>
                <input type="checkbox" name="単価" value="単価">
                <label for="text">単価</label>
            </div>
            <div>
                <input type="checkbox" name="単価_0" value="単価_0">
                <label for="text">単価_0</label>
            </div>
            <div>
                <input type="checkbox" name="単価_1" value="単価_1">
                <label for="text">単価_1</label>
            </div>
            <div>
                <input type="checkbox" checked name="数量" value="数量">
                <label for="text">数量</label>
            </div>

            <div>
                <input type="checkbox" checked name="数量_0" value="数量_0">
                <label for="text">数量_0</label>
            </div>
            <div>
                <input type="checkbox" checked name="数量_1" value="数量_1">
                <label for="text">数量_1</label>
            </div>
            <div class="button">
                <button type="button" id="button_submit">保存</button>
                <button type="button" id="button_cancel">キャンセル</button>
            </div>
        </div>
    </body>
</html>
```

# フィールドゼロ埋めJavaScriptカスタマイズ
kintoneアプリのフィールドをゼロ埋めするカスタマイズを作成します。
この時にプラグインの設定値を取得したと仮定してダミーデータを作り、それを利用してカスタマイズしていきます。

### カスタマイズ概要
以下のような内容です。

 - 編集画面、新規作成画面から保存する際に実行
 - プラグインの設定値を取得（ダミーです）
 - 単価フィールドが空欄の時にフィールドにゼロをセットする
 - 保存する 

テストですので、簡単に作ります。

長くなりますので、続きます。