【kintone】フィールド値更新でハマりがちなこと

こんにちは！
今日は、私がカスタマイズを初めて間もない頃にハマった

「値が表示できないぞ！」

についてです。

別アプリのレコードのデータを使って、フィールド値を更新したいときにハマりがちなところかと思います。
読んでみて、やってみてね！


# 作りたい目標アプリ

| マスターアプリ | ドロップダウンで値をとってくる |
|:-:|:-:|
| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/bd495c8c-7c39-c92d-916c-5ce5370c00e8.png)  |  ![1110.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/ed246b5a-0ccd-f82e-f631-b54c4a31d9ef.gif)
|


# マスターアプリを作る
マスター？、マスタ？
呼び出し元となるデータを置いとくアプリを作ります。

作り方はかんたん

|フィールド種類| フィールドコード |
|:-:|:-:|
| ドロップダウン  | カテゴリ  |
| 文字列(1行)  | 名前  |

|ドロップダウンの選択肢|
|:-:|
|文具|
|おやつ|

登録するレコード

|カテゴリ|名前|
|:-:|:-:|
|おやつ|チョコレート|
|おやつ|プロテイン|
|文具|鉛筆|
|文具|消しゴム|

↓こんな感じになったらOK

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/bd495c8c-7c39-c92d-916c-5ce5370c00e8.png" width=500>

# 呼び出し側のアプリを作る

|フィールド種類|フィールドコード|
|:-:|:-:|
|ドロップダウン|カテゴリ（中身はマスターアプリと同じ）|
|文字列(複数行)|内容|

↓こんな感じになったらOK

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/b9c595d2-bac2-96fd-d013-4f17b1fceb65.png" width="400">

# JavaScriptを書く

それでは、コードを書いていこうと思います。
こちらは呼び出し側アプリのJavaScriptとなります。

## フィールド値変更イベントを拾う

↓このあたりを参考に、「カテゴリ」フィールド値変更イベントを拾います。
[レコード追加画面のフィールド値変更時イベント](https://developer.cybozu.io/hc/ja/articles/201941984#step3)
[レコード編集画面のフィールド値変更時イベント](https://developer.cybozu.io/hc/ja/articles/202166270#step3)

↓こんな感じ

```js
(()=>{
    kintone.events.on([
        'app.record.create.change.カテゴリ', //新規・カテゴリフィールド変更イベント
        'app.record.edit.change.カテゴリ' //編集・カテゴリフィールド変更イベント
    ],  event => {
        //ここに処理を書く
        return event;
    });
})();
```

## マスターアプリからレコードを持ってくる
kintone REST API を使って、選択したカテゴリのレコードを一括取得します。
参考：[レコードの一括取得（クエリで条件を指定）](https://developer.cybozu.io/hc/ja/articles/202331474#step2)


```js

        let body = {
            'app': マスターアプリのアプリID,
            //↓これは、ドロップダウンで選択したカテゴリのレコードだけ取ってくるクエリ
            'query':`カテゴリ in("${event.record.カテゴリ.value}")`
        };
        
        //REST API（GET)を叩いて、データを持ってくる
        kintone.api('/k/v1/records', 'GET', body,(resp)=>{
            //ここで持ってきたデータを処理して、内容フィールドに表示する
        });

```

## 取得したデータを処理して、内容フィールドに表示する

```js
        kintone.api('/k/v1/records', 'GET', body,(resp)=>{
            let retStr ="";
            //resp.records内の「名前」フィールドを改行挟んで連結している
            resp.records.forEach(r => {
                retStr +=  r.名前.value + "\n";
            });

            //「内容」フィールドに連結した「名前」を表示する
            event.record.内容.value = retStr;
        });
```


## ひとまずコードが出来上がり。
しかし、これだとうまくいきません

```js
(()=>{

    kintone.events.on([
        'app.record.create.change.カテゴリ', //新規・カテゴリフィールド変更イベント
        'app.record.edit.change.カテゴリ' //編集・カテゴリフィールド変更イベント
    ],  event => {

        let body = {
            'app':  マスターアプリのアプリID,
            //↓これは、ドロップダウンで選択したカテゴリのレコードだけ取ってくるクエリ
            'query':`カテゴリ in("${event.record.カテゴリ.value}")`
        };
        
        //REST API（GET)を叩いて、データを持ってくる
        kintone.api('/k/v1/records', 'GET', body,(resp)=>{
            let retStr ="";
            //resp.records内の「名前」フィールドを改行挟んで連結している
            resp.records.forEach(r => {
                retStr +=  r.名前.value + "\n";
            });

            //「内容」フィールドに連結した「名前」を表示する
            event.record.内容.value = retStr;
        });

        return event;
    });
})();

```

## ここ変えよう

この部分が思ったように動かない原因となります。

```js
            //「内容」フィールドに連結した「名前」を表示する
            event.record.内容.value = retStr;
```

理由は・・・
フィールドにデータをセットする前に`event=>{～}`が終わっちゃってるからかな・・・。
`kintone.api()`が非同期なので。レコードにセットする頃にはイベントが終わっちゃってる。だと思います。
//正しい理由がわかる方いらっしゃったら教えて下さい・・・



## kintone.api(～)の中ではget&set使ってみよう！
というわけで、
event.recordに直接書き込むのではなく、get&setをつかいます。

```js
            //「内容」フィールドに連結した「名前」を表示する
            let obj = kintone.app.record.get();
            obj.record.内容.value = retStr;
            kintone.app.record.set(obj);
```

## できあがり
```js
(()=>{

    kintone.events.on([
        'app.record.create.change.カテゴリ', //新規・カテゴリフィールド変更イベント
        'app.record.edit.change.カテゴリ' //編集・カテゴリフィールド変更イベント
    ],  event => {

        let body = {
            'app':  マスターアプリのアプリID,
            //↓これは、ドロップダウンで選択したカテゴリのレコードだけ取ってくるクエリ
            'query':`カテゴリ in("${event.record.カテゴリ.value}")`
        };
        
        //REST API（GET)を叩いて、データを持ってくる
        kintone.api('/k/v1/records', 'GET', body,(resp)=>{
            let retStr ="";
            //resp.records内の「名前」フィールドを改行挟んで連結している
            resp.records.forEach(r => {
                retStr +=  r.名前.value + "\n";
            });

            //「内容」フィールドに連結した「名前」を表示する
            let obj = kintone.app.record.get();
            obj.record.内容.value = retStr;
            kintone.app.record.set(obj);
        });

        return event;
    });
})();

```

↓こんな感じになりましたでしょうか！？
![1110.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/ed246b5a-0ccd-f82e-f631-b54c4a31d9ef.gif)


# まとめ

kintone×JavaScriptって、非同期との戦いのことなのかなぁ・・・と思いました。
ちなみに、他のイベント（レコード追加/編集画面の表示後イベントなど）だと、
Promiseオブジェクトをreturnできるので、
getとset使わなくても

```js
return kintone.api(～～～).then(resp=>{
//event.record.内容の値を更新する
return event;
})

```
で値の更新ができます。
試してみてくださいね！