何も更新しない更新アプリでkintoneの自動再計算を実現したい

# はじめに
- ｲｼｲｹﾝﾀﾛｳです。ハケをつくっている会社の兼業情シスでkintoneを触る係をしてます
- kintone認定資格は3つ取得済です
- その他にITストラテジストやシステム監査技術者などの国家資格をいくつか取得しています
- kintoneのカスタマイズは社内向けのみで、プラグインは作ってません（作れません）
[![main_image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105085/564c7de8-6fc7-61c7-a97f-f8d0a7c9943d.jpeg)](https://www.maru-t.co.jp/painting_brush/)
![associate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105085/0a8e56b0-b57c-607c-b89b-19e793c78717.png) ![appdesignsp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105085/12705b5d-9006-2e8c-f9de-56ec7a22b611.png) ![customization.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105085/d318907a-f190-2542-82da-e6ee22e1498b.png)

# 自動計算フィールドを自動計算させたい
- 既存のアプリに計算フィールドや自動計算文字列1行フィールドを追加しても、そのままでは追加したフィールドに変化はありません
- excelのように自動的に計算させるには1レコードであれば一度編集画面を開いて保存する、複数レコードであればレコード番号を含んだcsvを書き出して同一csvを再度読み込む、といった作業が必要になります
- この作業が結構手間なので、アプリIDを入力してボタンクリックだけで自動計算できる専用アプリを作成します
- 元ネタは[斎藤さんの記事](https://developer.cybozu.io/hc/ja/articles/201883830-%E5%BE%8C%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%9F%E8%A8%88%E7%AE%97%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%81%AB%E4%B8%80%E6%8B%AC%E3%81%A7%E5%80%A4%E3%82%92%E5%8F%8D%E6%98%A0%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95)です
- きっかけはこのツイート
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">計算フィールドを追加したときに、過去のレコードにもその計算をさせたいのに保存をし直さないと反映されないやつ・・・。<br>みんなどうやって解決してるの？？</p>&mdash; たなよし＠UDフォント推奨派 (@tanaka4412) <a href="https://twitter.com/tanaka4412/status/1501798665949564934?ref_src=twsrc%5Etfw">March 10, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 完成イメージ
- ヘッダーにテキストボックスとボタンを置いただけです
- 一覧画面のヘッダーしか使わないのでフィールド何もいりません
![pcimage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105085/7156a528-e740-34b1-6c7d-aff199891824.png)
![spimage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105085/9415cf1f-1727-8f90-eb5d-60256f424482.png)

# 事前準備
- 「PC用のJavaScriptファイル」と「スマートフォン用のJavaScriptファイル」それぞれに以下を「URL指定で追加」してください（バージョンは必要に応じ適宜調整してください）
- 更新を行うために [kintone rest api client](https://developer.cybozu.io/hc/ja/articles/900000767263-kintone-JavaScript-Client-kintone-rest-api-client-)  を使います（https://js.cybozu.com/kintone-rest-api-client/2.0.35/KintoneRestAPIClient.min.js）
- テキストボックスとボタンを配置するために [kintone ui component v1](https://developer.cybozu.io/hc/ja/articles/900005544623-kintone-UI-Component-v1) を使います（https://unpkg.com/kintone-ui-component/umd/kuc.min.js）
- アラート表示は [SweetAlert](https://developer.cybozu.io/hc/ja/articles/204790870-SweetAlert-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6-kintone-%E3%81%A7%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AA%E3%83%83%E3%82%B7%E3%83%A5%E3%81%AB%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B%E3%82%88%E3%81%86-) を使います（https://js.cybozu.com/sweetalert/v2.1.2/sweetalert.min.js）
- 次のJSファイルを「PC用のJavaScriptファイル」と「スマートフォン用のJavaScriptファイル」それぞれに「アップロードして追加」してください
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105085/99e32e54-a1c1-d88e-bbd8-513b3d849fa9.png)


# JavaScript記述

``` javascript:emptyUpdatePC.js
/*
  ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
  ▼
  ▼                     アプリ空更新PC版
  ▼
  ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
*/
(() => {
    'use strict';

/*
  ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
  ●
  ●                          定数宣言
  ●
  ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
*/
  // kintone/rest-api-client設定 
  const client = new KintoneRestAPIClient();
/*
  ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
  ●
  ●                          イベント
  ●
  ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
*/
/*
  ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
    レコード一覧画面表示時
  ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
*/    
  kintone.events.on('app.record.index.show', (event) => {
        
    // 増殖バク回避
    if(document.getElementById('appIdText')){
      return event;
    }
    
    // ヘッダースペース取得
    const headerSpace = kintone.app.getHeaderMenuSpaceElement();
    
    // アプリIDテキストボックス
    const appIdText = new Kuc.Text({
      placeholder: 'アプリID',
      id: 'appIdText'
    });

    // アプリIDテキストボックスをヘッダースペースに追加
    headerSpace.appendChild(appIdText);

    // アプリ空更新ボタン
    const emptyUpdateButton = new Kuc.Button({
      text: 'アプリ空更新',
      type: 'submit',
      id: 'emptyUpdateButton'
    });
    
    // アプリ空更新ボタンクリック時
    emptyUpdateButton.addEventListener('click', async () => {

      // アプリIDの取得
      const appId = document.getElementById('appIdText').value;

      // アプリID未入力の場合は何もしない
      if(appId === ''){
        return;
      }

      // レコード取得用パラメータ(レコード番号だけ)
      const paramGet = {
          'app': appId,
          'fields': ['__ID__']
      };

      // レコード取得
      const respGet = await client.record.getAllRecords(paramGet);

      // 取得したレコード番号をそのまま更新用レコードとする
      const paramRecords = [];
      respGet.forEach((record) => {
          paramRecords.push({'id': record.$id.value});
      });
      
      // レコード更新用パラメータ
      const paramPut = {
          'app': appId,
          'records': paramRecords
      };
      
      // レコード更新
      const respPut = await client.record.updateAllRecords(paramPut);

      // アプリ名を取得して完了アラート
      const paramGetApp = {
          'id': appId
      };
      const respGetApp = await kintone.api(kintone.api.url('/k/v1/app', true), 'GET', paramGetApp);
      swal(respGetApp.name + ' を空更新しました');

    });
    
    // アプリ空更新ボタンをヘッダースペースに追加
    headerSpace.appendChild(emptyUpdateButton);
    
  });    

})();
```
``` javascript:emptyUpdateSP.js
/*
  ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
  ▼
  ▼                    アプリ空更新SP版
  ▼
  ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
*/
(() => {
  'use strict';

/*
  ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
  ●
  ●                          定数宣言
  ●
  ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
*/
  // kintone/rest-api-client設定 
  const client = new KintoneRestAPIClient();

/*
  ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
  ●
  ●                          イベント
  ●
  ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
*/
/*
  ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
    レコード一覧画面表示時
  ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
*/    
  kintone.events.on('mobile.app.record.index.show', (event) => {
        
    // 増殖バク回避
    if(document.getElementById('appIdText')){
      return event;
    }
    
    // ヘッダースペース取得
    const headerSpace = kintone.mobile.app.getHeaderSpaceElement();
    
    // アプリIDテキストボックス
    const appIdText = new Kuc.MobileText({
      placeholder: 'アプリID',
      id: 'appIdText'
    });
    // アプリIDテキストボックスをヘッダースペースに追加
    headerSpace.appendChild(appIdText);

    // アプリ空更新ボタン
    const emptyUpdateButton = new Kuc.MobileButton({
      text: 'アプリ空更新',
      type: 'submit',
      id: 'emptyUpdateButton'
    });
    
    // アプリ空更新ボタンクリック時
    emptyUpdateButton.addEventListener('click', async () => {

      // アプリIDの取得
      const appId = document.getElementById('appIdText').value;
      // アプリID未入力の場合は何もしない
      if(appId === ''){
        return;
      }

      // レコード取得用パラメータ(レコード番号だけ)
      const paramGet = {
          'app': appId,
          'fields': ['__ID__']
      };
      // レコード取得
      const respGet = await client.record.getAllRecords(paramGet);

      // 取得したレコード番号をそのまま更新用レコードとする
      const paramRecords = [];
      respGet.forEach((record) => {
          paramRecords.push({'id': record.$id.value});
      });
      
      // レコード更新用パラメータ
      const paramPut = {
          'app': appId,
          'records': paramRecords
      };
      
      // レコード更新
      const respPut = await client.record.updateAllRecords(paramPut);

      // アプリ名を取得して完了アラート
      const paramGetApp = {
          'id': appId
      };
      const respGetApp = await kintone.api(kintone.api.url('/k/v1/app', true), 'GET', paramGetApp);
      swal(respGetApp.name + ' を空更新しました');

    });
    
    // アプリ空更新ボタンをヘッダースペースに追加
    headerSpace.appendChild(emptyUpdateButton);
    
  });    
})();

```
# おわりに

- IEでは動きません
- 見た目気になる方はmargin修正してください
- あ、ゲストスペースのアプリに対応させるの忘れた対応してませんスミマセン
- ご要望あれば別途記事書きます
- そして例によって塗装用ローラーもつくってます
[![main_image (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105085/d20f1b7b-355a-1524-829f-71fcd21bdfed.jpeg)](https://www.maru-t.co.jp/painting_roller/)