kintoneのJavaScriptカスタマイズ入門。最初の1本を動かすまで

公開 書いた人 大林 諒

kintoneの標準機能で作ったアプリは、必須項目や計算式までは画面の設定だけで組めます。ところが「区分が外注のときだけ外注先を必須にしたい」「終了日が開始日より前なら保存させたくない」となった時点で、設定画面では届かなくなります。その残りを埋めるのがJavaScriptカスタマイズです。この記事では、ファイルを置く場所、イベントの書き方、すぐ使える3つの例、よく使うAPI、REST APIの呼び方、デバッグ、壊したときの戻し方までを通して書きます。読み終わると、自分で書いた1本を管理者だけに当てて確かめ、全員に公開するところまで進められます。前提は、アプリを作って公開したことがあり、JavaScriptの if と関数が読めることです。

この記事の内容
  1. 先に決めること
  2. 何をどこに置くか
  3. イベントとハンドラーの書き方
  4. 最初の1本:3つの例
  5. よく使うAPI
  6. REST APIをJavaScriptから呼ぶ
  7. 定番の実装の考え方
  8. デバッグのしかた
  9. 壊したときの戻し方とテスト環境
  10. 公式がサポートしないことと、アップデートの注意
  11. できないことと、その代わり
  12. よく詰まるところ
  13. 次にやること

先に決めること

JavaScriptは書けば何でもできるように見えますが、入れたあとに一番手間がかかるのは保守です。書く前に次の4つを決めておくと、あとで困りません。

標準機能とプラグインで済まないか

必須は「必須項目にする」、重複の防止は「値の重複を禁止する」、合計や日付の差は計算フィールドで済みます。条件付きの表示のような定番の動きは、プラグインで出ていることも多いです。JavaScriptは書いた人がいなくなると誰も直せなくなるので、標準機能かプラグインで済まないものだけ書きます。

誰が設定するか

公式ヘルプには「kintoneのシステム管理者だけが、アプリにJavaScriptやCSSを適用できます」とあります。アプリの管理権限だけでは、ファイルを入れられません。社内でシステム管理者が別の人なら、ファイルを渡して入れてもらう流れを先に決めておきます。

ライトコースではJavaScriptやCSSのカスタマイズは使えず、料金ページでも拡張機能の欄が対象外です。使えるのはスタンダードコース(1ユーザー月額1,800円・税抜、最低10ユーザー)とワイドコースです。

フィールドコードを先に固める

JavaScriptはフィールドをフィールド名ではなくフィールドコードで指します。あとからフィールドコードを変えると、その名前を使っているコードが黙って動かなくなります。書き始める前に、使うフィールドのフィールドコードをフィールド名と同じ文字か、意味の分かる英字にそろえ、以後は変えないと決めます。

ファイルの持ち方

実際の運用では、手元のファイルを直してアップロードし直す形で回します。手元には日付入りの名前(例: estimate_20261022.js)で古い版を残しておくと、壊したときにすぐ戻せます。

何をどこに置くか

置き場所

アプリごとのJavaScriptは、アプリの設定画面に置きます。経路は次のとおりです。

  1. 一覧画面の右上の歯車[アプリを設定]をクリックします。
  2. [設定]タブを開きます。
  3. [カスタマイズ/サービス連携]の[JavaScript / CSSでカスタマイズ]をクリックします。
  4. [適用範囲]を選びます。
  5. ファイルを追加します。
  6. [保存]をクリックします。
  7. 右上の[アプリを更新]をクリックし、確認のダイアログでもう一度[アプリを更新]をクリックします。
アプリの設定の[設定]タブ。[カスタマイズ/サービス連携]の[JavaScript / CSSでカスタマイズ]の位置
アプリの設定の[設定]タブ。[カスタマイズ/サービス連携]の[JavaScript / CSSでカスタマイズ]の位置

[保存]だけでは反映されず、[アプリを更新]まで押して初めて効きます。

kintone全体に効かせる設定は「kintoneシステム管理」にもありますが、最初の1本はアプリごとに置きます。全体に置くと、関係ないアプリまで巻き込むからです。

適用範囲の3つ

適用範囲効く相手使いどころ
すべてのユーザーに適用全員。ゲストユーザーにも効く動作を確かめたあとの本番
アプリ管理者だけに適用そのアプリの管理者だけ書いたものを自分で試すとき
適用しない誰にも効かない不具合が出たときの一時停止

公式ヘルプも、全員に当てる前に「アプリ管理者だけに適用」で確かめるよう書いています。新しいコードは必ずこの順で出します。

[JavaScript / CSSでカスタマイズ]の画面。[適用範囲]の3つの選択肢
[JavaScript / CSSでカスタマイズ]の画面。[適用範囲]の3つの選択肢

PC用とスマートフォン用

この画面は「PC用とスマートフォン用(スマートフォンアプリを含む)とで分けてカスタマイズします」という作りです。PC用の欄に入れたファイルは、スマートフォンのブラウザーやスマートフォンアプリでは読まれません。スマートフォンでも同じ動きが要るなら、スマートフォン用の欄にもファイルを入れます。

ただし、同じファイルをそのまま入れても動きません。イベントの名前とAPIの名前がPCとモバイルで違うからです。

用途PCモバイル
一覧を表示した後app.record.index.showmobile.app.record.index.show
詳細を表示した後app.record.detail.showmobile.app.record.detail.show
追加画面で保存するときapp.record.create.submitmobile.app.record.create.submit
開いているレコードを取るkintone.app.record.get()kintone.mobile.app.record.get()
フィールドの表示切り替えkintone.app.record.setFieldShown()kintone.mobile.app.record.setFieldShown()
ボタンを置く場所(一覧)kintone.app.getHeaderMenuSpaceElement()kintone.mobile.app.getHeaderSpaceElement()

実際に回っている形では、処理を共通の関数にし、イベント名だけ両方並べて登録しています。

URL指定とアップロードの違い

ファイルの入れ方は[URL指定で追加]と[アップロードして追加]の2つです。

入れ方向いているもの気をつける点
アップロードして追加自分で書いたコード直すたびにアップロードし直し、[アプリを更新]する
URL指定で追加外部のライブラリ(日付処理など)置き場所のサーバーが止まると動かない。中身が勝手に変わらない版を指す

URLにはcybozu.com以外のドメインも指定できます。ファイルは種類ごとに30個まで入れられ、上から順に読み込まれます。ライブラリを使うコードは、ライブラリより下に置きます。順番はファイル名の左のアイコンをドラッグして入れ替えます。

外部のライブラリは、サイボウズのセキュアコーディングガイドラインに従い、バージョン番号が入ったURLで固定します。

イベントとハンドラーの書き方

基本の形

kintoneのJavaScriptは「この画面でこれが起きたら、この関数を動かす」という書き方をします。登録には kintone.events.on を使います。

(() => {
  'use strict';

  kintone.events.on('app.record.detail.show', (event) => {
    console.log(event.record);
    return event;
  });
})();

全体を (() => { ... })(); で囲むのは、変数をほかのファイルとぶつけないためです。サイボウズのコーディングガイドラインも、グローバル変数を避け、即時関数かブロックの中で変数を定義するよう書いています。ファイルは「UTF-8(BOMなし)」で保存します。

event の中には、そのイベントで使える情報が入っています。event.record が画面のレコードで、フィールドコードで値を取ります。

const amount = event.record['金額'].value;

数値フィールドの値は、数値ではなく文字列で返ってきます。足し算をする前に Number() で変換します。チェックボックスの値は文字列の配列、日付は 2026-10-22 の形の文字列です。

よく使うイベント

画面タイミングイベント名(PC)
一覧表示した後app.record.index.show
一覧インライン編集で保存するときapp.record.index.edit.submit
詳細表示した後app.record.detail.show
追加表示した後app.record.create.show
追加フィールドの値を変えたときapp.record.create.change.フィールドコード
追加保存するときapp.record.create.submit
追加保存に成功した後app.record.create.submit.success
編集表示した後app.record.edit.show
編集フィールドの値を変えたときapp.record.edit.change.フィールドコード
編集保存するときapp.record.edit.submit
編集保存に成功した後app.record.edit.submit.success
詳細プロセス管理のアクションを実行するときapp.record.detail.process.proceed

同じ処理を複数の画面で動かすときは、イベント名を配列で渡します。

kintone.events.on(['app.record.create.show', 'app.record.edit.show'], (event) => {
  return event;
});

値を変えたときのイベントは、どのフィールドでも使えるわけではありません。使えるのはラジオボタン、ドロップダウン、チェックボックス、複数選択、ユーザー選択、組織選択、グループ選択、日付、時刻、日時、文字列(1行)、数値、テーブル、ルックアップです。文字列(1行)と数値は、入力中ではなくフォーカスが外れたときに発生します。指定できないフィールドのフィールドコードを書いても、エラーにはならず何も起きません。

イベントの中でできること

ハンドラーの中で event を書き換えて return event; すると、kintoneがそれを画面に反映します。

やりたいこと書き方使えるイベントの例
値を書き換えるrecord['フィールド'].value = '値'追加・編集の表示、値変更、保存するとき
編集できなくするrecord['フィールド'].disabled = true追加・編集の表示、値変更
フィールドの下にエラーを出すrecord['フィールド'].error = 'メッセージ'追加・編集の表示、値変更、保存するとき
画面の上にエラーを出すevent.error = 'メッセージ'追加・編集の保存するとき、一覧のインライン編集の保存するとき
保存をやめさせるエラーを出すか return false;各画面の保存するとき

保存するときのイベントでは、エラーを出すか false を返すと保存が止まります。エラーを出したときは、同じハンドラーでの値の書き換えや編集可否の設定は取り消されます。

kintone.events.on で登録したハンドラーは、上書きではなく追加されます。同じファイルを2回入れると、同じ処理が2回動きます。

最初の1本:3つの例

3例とも、フィールドコードを書き換えるだけで動きます。例ごとにファイルを分けると、1つ壊れてもほかは止まりません。

例1:保存前のチェック(条件付き必須と日付の前後)

「終了日が開始日より前なら保存させない」「区分が外注のときだけ外注先を必須にする」の2つを入れます。区分はドロップダウン、開始日と終了日は日付、外注先は文字列(1行)です。

(() => {
  'use strict';

  // 問題があれば [フィールドコード, メッセージ] の組を返す
  const check = (record) => {
    const errors = [];
    const start = record['開始日'].value;
    const end = record['終了日'].value;
    if (start && end && end < start) {
      errors.push(['終了日', '終了日が開始日より前になっています']);
    }
    if (record['区分'].value === '外注' && !record['外注先'].value) {
      errors.push(['外注先', '区分が外注のときは外注先を入れてください']);
    }
    return errors;
  };

  // 追加画面と編集画面:フィールドの下にエラーを出す
  kintone.events.on(['app.record.create.submit', 'app.record.edit.submit'], (event) => {
    check(event.record).forEach(([code, message]) => {
      event.record[code].error = message;
    });
    return event;
  });

  // 一覧のインライン編集:画面の上にエラーを出す
  kintone.events.on('app.record.index.edit.submit', (event) => {
    const errors = check(event.record);
    if (errors.length > 0) {
      event.error = errors.map(([, message]) => message).join(' / ');
    }
    return event;
  });
})();

日付は 2026-10-22 の形の文字列なので、そのまま大小を比べられます。追加と編集のイベントだけだと、一覧で直接書き換えたときにチェックをすり抜けます。

編集画面で保存を押し、終了日の下に赤いエラーが出ている状態
編集画面で保存を押し、終了日の下に赤いエラーが出ている状態

例2:フィールドの表示と非表示

区分が外注のときだけ、外注先と外注費を見せます。

(() => {
  'use strict';

  const toggle = (record) => {
    const isOutsource = record['区分'].value === '外注';
    kintone.app.record.setFieldShown('外注先', isOutsource);
    kintone.app.record.setFieldShown('外注費', isOutsource);
  };

  // 画面を開いたとき
  kintone.events.on([
    'app.record.create.show',
    'app.record.edit.show',
    'app.record.detail.show',
  ], (event) => {
    toggle(event.record);
    return event;
  });

  // 区分を変えたとき
  kintone.events.on([
    'app.record.create.change.区分',
    'app.record.edit.change.区分',
  ], (event) => {
    toggle(event.record);
    return event;
  });
})();

表示した後と値を変えたときの両方に書くのが要点です。変えたときだけだと、保存済みのレコードを開いた瞬間は全部見えます。詳細画面も入れておかないと、詳細と編集で見え方がずれます。

setFieldShown はフィールドコードのほか、スペースやラベルに付けた要素IDも指定できます。テーブル内の1つのフィールドだけを隠すときはそのフィールドのフィールドコード、テーブルごと隠すときはテーブルのフィールドコードを渡します。

実際に動かすと、隠したフィールドも値を持ったまま保存されます。外注から社内に戻したときに外注先を消したいなら、app.record.edit.change.区分 の中で event.record['外注先'].value = ''; を足します。

区分を「外注」に切り替えた瞬間に外注先と外注費が現れた編集画面
区分を「外注」に切り替えた瞬間に外注先と外注費が現れた編集画面

例3:一覧にボタンを置く

一覧の上に「未対応の件数」ボタンを置き、押したら件数を出します。状態はドロップダウンです。

(() => {
  'use strict';

  kintone.events.on('app.record.index.show', (event) => {
    // 一覧の切り替えやページ送りでも発生するので、2つ目を置かない
    if (document.getElementById('count-open-button')) {
      return event;
    }

    const button = document.createElement('button');
    button.id = 'count-open-button';
    button.textContent = '未対応の件数';
    button.addEventListener('click', async () => {
      try {
        const resp = await kintone.api(kintone.api.url('/k/v1/records.json', true), 'GET', {
          app: kintone.app.getId(),
          query: '状態 in ("未対応") limit 1',
          totalCount: true,
        });
        alert(`未対応は ${resp.totalCount} 件です`);
      } catch (error) {
        console.error(error);
        alert('件数を取れませんでした');
      }
    });

    kintone.app.getHeaderMenuSpaceElement().appendChild(button);
    return event;
  });
})();

一覧を表示した後のイベントは、ページ送り、絞り込み、カテゴリーの変更、並べ替えでも発生します。重複を防ぐ if が無いと、ボタンが増えます。

getHeaderMenuSpaceElement は、集計アイコンの右側の場所を返します。PCのレコード一覧画面だけで使えるAPIで、モバイルでは kintone.mobile.app.getHeaderSpaceElement を使います。

一覧の集計アイコンの右に「未対応の件数」ボタンが並んだ状態
一覧の集計アイコンの右に「未対応の件数」ボタンが並んだ状態

よく使うAPI

開いているレコードを読む・書く

kintone.app.record.get() は開いているレコードを返し、kintone.app.record.set() は値を書き込みます。この2つは、ボタンのクリックのような普通のJavaScriptのイベントの中で使います。kintone.events.on のハンドラーの中では使えません。ハンドラーの中では event.record を読み書きして return event; します。

次の例は、編集画面のスペース(要素ID today_button)に「今日にする」ボタンを置き、押すと対応日に今日の日付を入れます。

(() => {
  'use strict';

  kintone.events.on(['app.record.create.show', 'app.record.edit.show'], (event) => {
    const space = kintone.app.record.getSpaceElement('today_button');
    if (!space || space.childElementCount > 0) {
      return event;
    }
    const button = document.createElement('button');
    button.type = 'button';
    button.textContent = '今日にする';
    button.addEventListener('click', () => {
      const d = new Date();
      const today = [
        d.getFullYear(),
        String(d.getMonth() + 1).padStart(2, '0'),
        String(d.getDate()).padStart(2, '0'),
      ].join('-');
      const current = kintone.app.record.get();
      current.record['対応日'].value = today;
      kintone.app.record.set(current);
    });
    space.appendChild(button);
    return event;
  });
})();

set は追加画面と編集画面でしか使えません。添付ファイルの値は書き換えられません。

スペースの要素IDは、フォームでスペースを置いて設定を開くと入れられます。アルファベットで始まる64文字までで、ほかのフィールドの要素IDと同じ値は使えません。

フォームの設定で[スペース]の設定を開き、[要素ID]に today_button と入れたところ
フォームの設定で[スペース]の設定を開き、[要素ID]に today_button と入れたところ

そのほかの定番

API何を返すか・何をするか使える画面(PC)
kintone.app.getId()開いているアプリのアプリID一覧・詳細・追加・編集・印刷・グラフ
kintone.app.record.getId()開いているレコードのレコードID詳細・編集・印刷
kintone.app.record.getSpaceElement('要素ID')スペースの場所詳細・追加・編集・印刷
kintone.app.record.getHeaderMenuSpaceElement()詳細などでメニューの上側の場所詳細・追加・編集
kintone.app.getHeaderMenuSpaceElement()一覧で集計アイコンの右側の場所一覧
kintone.app.record.setFieldShown()フィールドの表示・非表示詳細・追加・編集・印刷

アプリIDは数字で書かず kintone.app.getId() で取ります。複製したアプリで試すとIDが変わるからです。

REST APIをJavaScriptから呼ぶ

kintone.api の形

別のレコードを読んだり、ほかのアプリに書き込んだりするときは、kintone.api でkintone REST APIを呼びます。

const resp = await kintone.api(
  kintone.api.url('/k/v1/records.json', true),
  'GET',
  { app: kintone.app.getId(), query: '状態 in ("未対応") order by $id desc limit 100' }
);
console.log(resp.records);

1つ目の引数はURLです。kintone.api.url の2つ目に true を渡すと、ゲストスペースの中で動いたときにゲストスペース用のURLになります。どちらで使われてもいいように true を付けておきます。2つ目はGET・POST・PUT・DELETEのどれか、3つ目がパラメーターです。成功時と失敗時の関数を省くとPromiseが返るので、await と try/catch で書けます。

画面から呼ぶ kintone.api は、ログインしている人のセッションで動きます。ヘッダーを自分で付ける必要はありません。

APIトークンを使う外部からの呼び方、クエリの細かい書き方は、「kintone REST APIの使い方。APIトークンの発行からレコードの取得・登録まで」に分けて書いています。

取得の上限

複数のレコードを取るAPIは、1回で最大500件です。limit を省くと100件になります。offset は10,000までです。それより多いレコードを扱うときは、$id で区切って順に取る書き方にします。

詳細画面から別の値を更新する

詳細画面に「完了にする」ボタンを置き、押したら状態を完了に更新して画面を読み直す例です。

(() => {
  'use strict';

  kintone.events.on('app.record.detail.show', (event) => {
    if (event.record['状態'].value === '完了' || document.getElementById('done-button')) {
      return event;
    }
    const button = document.createElement('button');
    button.id = 'done-button';
    button.textContent = '完了にする';
    button.addEventListener('click', async () => {
      button.disabled = true;
      try {
        await kintone.api(kintone.api.url('/k/v1/record.json', true), 'PUT', {
          app: kintone.app.getId(),
          id: kintone.app.record.getId(),
          record: { 状態: { value: '完了' } },
        });
        location.reload();
      } catch (error) {
        console.error(error);
        alert('更新できませんでした');
        button.disabled = false;
      }
    });
    kintone.app.record.getHeaderMenuSpaceElement().appendChild(button);
    return event;
  });
})();

1件を更新するAPIでは、計算、ステータス、作業者、作成者、更新者、ルックアップでコピーされるフィールドなどは書き換えられません。テーブルを更新するときは、残したい行も全部送ります。送らなかった行は消えます。ここは本番データを消す事故がいちばん起きやすい所です。

詳細画面のメニューの上に「完了にする」ボタンが出ている状態
詳細画面のメニューの上に「完了にする」ボタンが出ている状態

定番の実装の考え方

条件付き必須

標準の「必須項目にする」は条件を付けられません。条件付きにするなら、フィールドの必須はオフにして、例1のように保存するときのイベントでエラーを出します。例2と組み合わせて「見えているときだけ必須」にすると、入力する人にも分かりやすくなります。

隠すフィールドに標準の「必須項目にする」を付けたままにすると、入れようのない項目で保存が止まる、という相談が実際に多いです。

自動採番

標準のレコード番号は作った順の連番で、削除したら欠番になり、番号の変更や書式の指定はできません。公式ヘルプも、独自の書式で振るならJavaScriptで、と書いています。アプリコードを設定すれば「client-1」のような形にはなるので、それで足りるならJavaScriptは要りません。

「Q2026-0001」のように年ごとに振り直したいときは、追加画面で保存するときに最後のレコードの番号を読み、1を足して入れます。

(() => {
  'use strict';

  kintone.events.on('app.record.create.submit', async (event) => {
    const year = `Q${new Date().getFullYear()}`;
    const resp = await kintone.api(kintone.api.url('/k/v1/records.json', true), 'GET', {
      app: kintone.app.getId(),
      query: 'order by $id desc limit 1',
      fields: ['管理番号'],
    });
    const last = resp.records.length > 0 ? resp.records[0]['管理番号'].value : '';
    const [lastYear, lastNo] = last.split('-');
    const next = lastYear === year ? Number(lastNo) + 1 : 1;
    event.record['管理番号'].value = `${year}-${String(next).padStart(4, '0')}`;
    return event;
  });
})();

保存するときのイベントはPromiseに対応しているので、async の関数を渡せばAPIの返事を待ってから保存されます。管理番号には「値の重複を禁止する」を付けます。2人が同時に保存して同じ番号を取っても、後の人の保存がエラーで止まり、押し直せば次の番号が入ります。追加画面と編集画面では disabled = true にして手で変えられないようにします。

タブ表示

フィールドの種類にタブはありません。近いのはグループで、折りたたみと展開ができます。ただしグループの中にテーブルやグループは入れられません。

タブで切り替えたいときは、フォームの一番上にスペース(要素ID例 tabs)を置いてボタンを並べ、押したボタンに応じて setFieldShown でフィールドを出し分けます。自作よりプラグインのほうが保守は楽です。フォームの組み方そのものは「フォームのレイアウトの作り方。グループ・スペース・ラベルで見やすくする」に書いています。

デバッグのしかた

開発者ツールを開く

動かないときは、ブラウザーの開発者ツールを開きます。Chromeなら、Windowsは Ctrl + Shift + J、Macは Cmd + Option + J でコンソールが開きます。メニューからは、右上の縦三点から「その他のツール」、「デベロッパー ツール」の順です。

【画面:kintoneの一覧画面でChromeの開発者ツールのコンソールを開いたところ】

見る順番

  1. コンソールに赤いエラーが出ていないか見ます。出ていれば、ファイル名と行番号が書いてあります。
  2. ハンドラーの先頭に console.log(event); を入れて、そもそもイベントが動いているか見ます。何も出なければ、イベント名の綴りか、PC用・スマートフォン用の欄の間違いです。
  3. event.record を開いて、フィールドコードが合っているか見ます。Cannot read properties of undefined が出ていれば、ほぼフィールドコードの違いです。
  4. 値の形を見ます。数値が文字列で入っている、チェックボックスが配列になっている、という所でよく止まります。

止めて1行ずつ見る

コンソールで足りないときは、[ソース]パネルで止めます。左のツリーから自分のファイルを開き、行番号をクリックするとブレークポイントが付きます。画面を操作してその行に来ると止まり、[Scope]タブで変数の中身が見られます。ステップ実行のボタンで1行ずつ進めます。

【画面:Chromeの[ソース]パネルで自分のjsファイルの行番号にブレークポイントを付けたところ】

壊したときの戻し方とテスト環境

その場で止める

全員の画面が動かなくなったら、まず[適用範囲]を「適用しない」にして保存し、[アプリを更新]します。これでカスタマイズが外れ、標準のアプリとして使える状態に戻ります。止めてから、手元の古い版をアップロードし直します。

kintone全体のカスタマイズが原因のときは、「kintoneシステム管理」の[JavaScript / CSSでカスタマイズ]で同じように「適用しない」にします。どちらもシステム管理者の権限が要ります。

[保存]だけでまだ[アプリを更新]していない変更は、設定画面の[変更を破棄]で捨てられます。

設定変更の履歴

[運用管理]の[設定変更の履歴]で、いつ誰がどの設定を変えたかは見られます。戻すボタンではないので、戻すのは手元のファイルでやります。

動作テスト環境

[運用管理]の[アプリの動作テスト]を使うと、本番のレコードに触れずに画面を試せます。アプリにカスタマイズを当てると、PC版の動作テスト環境にも同じカスタマイズが当たります。

落とし穴は、動作テスト環境の中でも、URLに /preview/ を含まないREST APIは本番のデータに効くことです。「完了にする」ボタンは、動作テスト環境で押しても本番のレコードを書き換えます。また、動作テスト環境では通知は送られず、Webhookなどの外部連携も動きません。

コード側で分けたいときは、kintone.app.isTestEnvironment() で動作テスト環境かどうかがPromiseで返ります。

[設定]タブの[運用管理]。[アプリの動作テスト]と[設定変更の履歴]の位置
[設定]タブの[運用管理]。[アプリの動作テスト]と[設定変更の履歴]の位置

アプリを複製して試す

REST APIで書き込むコードは、本番とは別のアプリで試します。アプリの作成から[ほかのアプリを再利用]を選ぶと、フォームや設定を写したアプリができます。レコード、APIトークン、Webhook、プラグインに入れた設定は引き継がれません。カスタマイズのファイルは、複製したあとに[JavaScript / CSSでカスタマイズ]を開いて入っているかを確かめ、無ければ同じファイルを入れます。テスト用のレコードは数件、ファイルの読み込みか手で入れます。

開発用の環境

本番と完全に分けたいなら、cybozu developer networkの開発者ライセンスがあります。無料で12か月、5ユーザー、スタンダードコースにほぼ相当する環境です。本番の運用には使えません。

公式がサポートしないことと、アップデートの注意

サポートの範囲

サイボウズのサポートは、APIの仕様の問い合わせは受けますが、API、JavaScript、CSSを使ったカスタマイズの問い合わせは受け付けていません。動かないときに頼れるのは、cybozu developer networkの資料と、自社か依頼先の開発者です。

kintoneのアップデートで壊れるもの

サイボウズのコーディングガイドラインには、画面の要素に付いているidやclassの値は「予告なく変更されます」、画面の構造も「変更されることがあります」と書いてあります。開発者ツールで見つけたclass名で document.querySelector を使うコードは、ある日のアップデートで突然動かなくなります。

PCには旧デザインと新デザインがあり、kintone.getUiVersion() が 2 ならPCの新デザインです。画面の構造に頼ったコードは、デザインが切り替わった時点で壊れます。

ボタンを置く場所は getHeaderMenuSpaceElement や getSpaceElement、表示の切り替えは setFieldShown のように、kintoneが用意したAPIだけで書きます。この記事のコードは全部その範囲に収めてあります。

安全のために守ること

  • 入力された値を画面に出すときは innerHTML ではなく innerText を使います。
  • パスワードやAPIトークンをJavaScriptに書きません。ファイルは利用者のブラウザーに届くので、誰でも読めます。
  • アプリとプラグインの両方にJavaScriptがあるときは、公式の確認時点(2017年5月版)ではアプリのほうが先に読み込まれます。

できないことと、その代わり

やりたいこと標準のJavaScriptで代わりの手
CSVの読み込みやREST APIで入ったデータもチェックする画面のイベントは動かないので、すり抜ける読み込む前にExcelでチェックする。定期的に条件で一覧を作って洗い出す
ファイルのアップロード・ダウンロードを kintone.api で使えないfetch を使う
外部のAPIを鍵付きで呼ぶ鍵をJavaScriptに置けないプラグインのプロキシに鍵を置く。サーバー側で中継する
外部サイトへブラウザーから直接通信ドメインの制約で通らないkintone.proxy を使う
スレッドやスペースのお知らせに貼ったアプリで動かすカスタマイズは適用されないアプリを直接開いてもらう
スマートフォンで一覧にボタンPC用のAPIは使えないモバイル用のAPIで別に書く

JavaScriptのチェックは画面で入力する人のためのものと割り切り、データとして守りたい条件は「値の重複を禁止する」など標準の入力制限でかけます。プラグインの選び方は「kintoneのプラグインとは。入れ方・選び方・注意点」で比べています。

よく詰まるところ

症状原因直し方
メニューに[JavaScript / CSSでカスタマイズ]があるのに設定できないシステム管理者でないシステム管理者にファイルを渡して入れてもらう
直したのに動きが変わらない[保存]だけで[アプリを更新]していない[アプリを更新]を押し、ブラウザーを再読み込みする
自分では動くのにほかの人の画面で動かない適用範囲が「アプリ管理者だけに適用」のまま確かめ終わったら「すべてのユーザーに適用」にする
スマートフォンだけ動かないPC用の欄にしか入れていない、またはPC用のイベント名のままスマートフォン用の欄に mobile. のイベントで書いたファイルを入れる
Cannot read properties of undefined が出るフィールドコードがフィールド名と違う、または後から変えたフォームの設定でフィールドコードを確かめて合わせる
足し算が「1020」のように文字がつながる数値フィールドの値が文字列Number() で変換してから計算する
値を入れたのに画面に反映されないreturn event; を書き忘れたハンドラーの最後で必ず event を返す
ボタンが2つ3つと増える一覧の表示イベントがページ送りや絞り込みでも発生する置く前に同じidの要素が無いかを確かめる
一覧で直接書き換えるとチェックをすり抜けるインライン編集は別のイベントapp.record.index.edit.submit にも同じチェックを書く
kintone.app.record.get() が動かないkintone.events.on のハンドラーの中で呼んでいるハンドラーの中では event.record を使う
隠した項目のせいで保存できない(実際によくある相談)隠したフィールドに「必須項目にする」が付いている標準の必須を外し、保存するときのイベントで条件付きにする
テーブルの行が消えた1件更新のAPIで一部の行だけ送った残す行も全部送る。消えた行は手元の記録から入れ直す
動作テストで押したら本番のデータが変わった動作テスト環境でも /preview/ の無いREST APIは本番に書き込む書き込むコードは複製したアプリで試す
一覧のインライン編集のチェックで計算フィールドが空になるインライン編集で保存するときのイベントでは、計算フィールドは再計算前の値か空文字計算結果に頼るチェックは、JavaScript側で同じ計算をしてから比べる

次にやること

最初の1本は例1がおすすめで、壊れても保存が止まるだけで済みます。「アプリ管理者だけに適用」で1日使い、問題なければ全員に出します。

別のアプリのデータを読んだり、外部から登録したりするなら「kintone REST APIの使い方。APIトークンの発行からレコードの取得・登録まで」へ進みます。コードを書く前に既製品で済まないか調べるなら「kintoneのプラグインとは。入れ方・選び方・注意点」、JavaScriptを使わずに済む計算は「計算式の書き方。条件分岐(IF)と日付計算のパターン集」、見せ方の工夫は「フォームのレイアウトの作り方。グループ・スペース・ラベルで見やすくする」に書いています。

あわせて読む