kintoneの標準機能で作ったアプリは、必須項目や計算式までは画面の設定だけで組めます。ところが「区分が外注のときだけ外注先を必須にしたい」「終了日が開始日より前なら保存させたくない」となった時点で、設定画面では届かなくなります。その残りを埋めるのがJavaScriptカスタマイズです。この記事では、ファイルを置く場所、イベントの書き方、すぐ使える3つの例、よく使うAPI、REST APIの呼び方、デバッグ、壊したときの戻し方までを通して書きます。読み終わると、自分で書いた1本を管理者だけに当てて確かめ、全員に公開するところまで進められます。前提は、アプリを作って公開したことがあり、JavaScriptの if と関数が読めることです。
この記事の内容
先に決めること
JavaScriptは書けば何でもできるように見えますが、入れたあとに一番手間がかかるのは保守です。書く前に次の4つを決めておくと、あとで困りません。
標準機能とプラグインで済まないか
必須は「必須項目にする」、重複の防止は「値の重複を禁止する」、合計や日付の差は計算フィールドで済みます。条件付きの表示のような定番の動きは、プラグインで出ていることも多いです。JavaScriptは書いた人がいなくなると誰も直せなくなるので、標準機能かプラグインで済まないものだけ書きます。
誰が設定するか
公式ヘルプには「kintoneのシステム管理者だけが、アプリにJavaScriptやCSSを適用できます」とあります。アプリの管理権限だけでは、ファイルを入れられません。社内でシステム管理者が別の人なら、ファイルを渡して入れてもらう流れを先に決めておきます。
ライトコースではJavaScriptやCSSのカスタマイズは使えず、料金ページでも拡張機能の欄が対象外です。使えるのはスタンダードコース(1ユーザー月額1,800円・税抜、最低10ユーザー)とワイドコースです。
フィールドコードを先に固める
JavaScriptはフィールドをフィールド名ではなくフィールドコードで指します。あとからフィールドコードを変えると、その名前を使っているコードが黙って動かなくなります。書き始める前に、使うフィールドのフィールドコードをフィールド名と同じ文字か、意味の分かる英字にそろえ、以後は変えないと決めます。
ファイルの持ち方
実際の運用では、手元のファイルを直してアップロードし直す形で回します。手元には日付入りの名前(例: estimate_20261022.js)で古い版を残しておくと、壊したときにすぐ戻せます。
何をどこに置くか
置き場所
アプリごとのJavaScriptは、アプリの設定画面に置きます。経路は次のとおりです。
- 一覧画面の右上の歯車[アプリを設定]をクリックします。
- [設定]タブを開きます。
- [カスタマイズ/サービス連携]の[JavaScript / CSSでカスタマイズ]をクリックします。
- [適用範囲]を選びます。
- ファイルを追加します。
- [保存]をクリックします。
- 右上の[アプリを更新]をクリックし、確認のダイアログでもう一度[アプリを更新]をクリックします。
![アプリの設定の[設定]タブ。[カスタマイズ/サービス連携]の[JavaScript / CSSでカスタマイズ]の位置](https://nexly.co.jp/kintone/wp-content/uploads/2026/10/kintone-19-01.jpg)
[保存]だけでは反映されず、[アプリを更新]まで押して初めて効きます。
kintone全体に効かせる設定は「kintoneシステム管理」にもありますが、最初の1本はアプリごとに置きます。全体に置くと、関係ないアプリまで巻き込むからです。
適用範囲の3つ
| 適用範囲 | 効く相手 | 使いどころ |
|---|---|---|
| すべてのユーザーに適用 | 全員。ゲストユーザーにも効く | 動作を確かめたあとの本番 |
| アプリ管理者だけに適用 | そのアプリの管理者だけ | 書いたものを自分で試すとき |
| 適用しない | 誰にも効かない | 不具合が出たときの一時停止 |
公式ヘルプも、全員に当てる前に「アプリ管理者だけに適用」で確かめるよう書いています。新しいコードは必ずこの順で出します。
![[JavaScript / CSSでカスタマイズ]の画面。[適用範囲]の3つの選択肢](https://nexly.co.jp/kintone/wp-content/uploads/2026/10/kintone-19-02.jpg)
PC用とスマートフォン用
この画面は「PC用とスマートフォン用(スマートフォンアプリを含む)とで分けてカスタマイズします」という作りです。PC用の欄に入れたファイルは、スマートフォンのブラウザーやスマートフォンアプリでは読まれません。スマートフォンでも同じ動きが要るなら、スマートフォン用の欄にもファイルを入れます。
ただし、同じファイルをそのまま入れても動きません。イベントの名前とAPIの名前がPCとモバイルで違うからです。
| 用途 | PC | モバイル |
|---|---|---|
| 一覧を表示した後 | app.record.index.show | mobile.app.record.index.show |
| 詳細を表示した後 | app.record.detail.show | mobile.app.record.detail.show |
| 追加画面で保存するとき | app.record.create.submit | mobile.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 と入れたところ](https://nexly.co.jp/kintone/wp-content/uploads/2026/10/kintone-19-06.jpg)
そのほかの定番
| 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の開発者ツールのコンソールを開いたところ】
見る順番
- コンソールに赤いエラーが出ていないか見ます。出ていれば、ファイル名と行番号が書いてあります。
- ハンドラーの先頭に
console.log(event);を入れて、そもそもイベントが動いているか見ます。何も出なければ、イベント名の綴りか、PC用・スマートフォン用の欄の間違いです。 event.recordを開いて、フィールドコードが合っているか見ます。Cannot read properties of undefinedが出ていれば、ほぼフィールドコードの違いです。- 値の形を見ます。数値が文字列で入っている、チェックボックスが配列になっている、という所でよく止まります。
止めて1行ずつ見る
コンソールで足りないときは、[ソース]パネルで止めます。左のツリーから自分のファイルを開き、行番号をクリックするとブレークポイントが付きます。画面を操作してその行に来ると止まり、[Scope]タブで変数の中身が見られます。ステップ実行のボタンで1行ずつ進めます。
【画面:Chromeの[ソース]パネルで自分のjsファイルの行番号にブレークポイントを付けたところ】
壊したときの戻し方とテスト環境
その場で止める
全員の画面が動かなくなったら、まず[適用範囲]を「適用しない」にして保存し、[アプリを更新]します。これでカスタマイズが外れ、標準のアプリとして使える状態に戻ります。止めてから、手元の古い版をアップロードし直します。
kintone全体のカスタマイズが原因のときは、「kintoneシステム管理」の[JavaScript / CSSでカスタマイズ]で同じように「適用しない」にします。どちらもシステム管理者の権限が要ります。
[保存]だけでまだ[アプリを更新]していない変更は、設定画面の[変更を破棄]で捨てられます。
設定変更の履歴
[運用管理]の[設定変更の履歴]で、いつ誰がどの設定を変えたかは見られます。戻すボタンではないので、戻すのは手元のファイルでやります。
動作テスト環境
[運用管理]の[アプリの動作テスト]を使うと、本番のレコードに触れずに画面を試せます。アプリにカスタマイズを当てると、PC版の動作テスト環境にも同じカスタマイズが当たります。
落とし穴は、動作テスト環境の中でも、URLに /preview/ を含まないREST APIは本番のデータに効くことです。「完了にする」ボタンは、動作テスト環境で押しても本番のレコードを書き換えます。また、動作テスト環境では通知は送られず、Webhookなどの外部連携も動きません。
コード側で分けたいときは、kintone.app.isTestEnvironment() で動作テスト環境かどうかがPromiseで返ります。
![[設定]タブの[運用管理]。[アプリの動作テスト]と[設定変更の履歴]の位置](https://nexly.co.jp/kintone/wp-content/uploads/2026/10/kintone-19-10.jpg)
アプリを複製して試す
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)と日付計算のパターン集」、見せ方の工夫は「フォームのレイアウトの作り方。グループ・スペース・ラベルで見やすくする」に書いています。