関連レコード一覧フィールドは関連性が1:Nの場合は標準機能で設定できますが、テーブルの内容を条件とするような、関連性がN:Nの場合は標準機能で設定できません。
こちらの
cybozu developer communityでの回答
のように詳細データ設定用のアプリを別途作成して、標準機能で対応する方法もあります。
しかし今回は、JavaScript APIを利用して関連レコード一覧のテーブルを作成・表示するカスタマイズ方法を説明したいと思います。
デモ環境で実際に動作を確認できます。
https://dev-demo.cybozu.com/k/295/
ログイン情報は
cybozu developer networkデモ環境
で確認してください。
kintoneアプリの作成
固定リンクがコピーされました
サンプルのアプリとして、学習塾クラスの管理アプリを作成します。
生徒管理アプリとクラス管理アプリを作成して、生徒管理アプリから複数のクラスをルックアップ選択し、クラス管理アプリでは、そのクラスに登録した生徒を一覧表示するように設定します。
1人の生徒が複数のクラスを選択でき、ひとつのクラスには複数の生徒が登録されるので、N:Nの関連性となります。
クラス管理アプリの作成
固定リンクがコピーされました
次の画像とテーブルを参考にクラス管理アプリを作成します。
フィールドの種類 |
フィールド名 |
フィールドコード |
備考 |
レコード番号 |
クラス番号 |
class_no |
|
文字列(1行) |
クラスコード |
class_code |
|
文字列(1行) |
クラス名 |
class_name |
|
スペース |
|
student_list |
テーブル表示スペース |
生徒管理アプリの作成
固定リンクがコピーされました
次の画像とテーブルを参考に生徒管理アプリを作成します。
フィールドの種類 |
フィールド名 |
フィールドコード |
備考 |
レコード番号 |
生徒番号 |
student_no |
|
文字列(1行) |
生徒コード |
student_code |
|
文字列(1行) |
氏名 |
student_name |
|
ルックアップ |
クラスコード |
class_code |
テーブル |
文字列(1行) |
クラス名 |
class_name |
テーブル |
作成した「クラス管理アプリ」に次のソースコードを参考にしたJavaScriptファイルを作成し、適用します。
テーブルのHTMLのクラス名は、kintoneのスタイルに調和するよう、
51-modern-default
を参考にしています。
こちらの
GitHub上のスタイルシート
をダウンロードし、アプリに反映してください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
/*
* N:N(複数対複数)の関連レコード一覧を自作する
* Copyright (c) 2025 Cybozu
*
* Licensed under the MIT License
*/
(() => {
'use strict';
// HTMLエスケープ関数
const escapeHtml = (str) => {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
};
// 生徒一覧テーブルの作成
const generateStudentTableHtml = (records, subAppId) => {
const rows = records
.map((rec) => {
const id = escapeHtml(record.$id.value);
const code = escapeHtml(record.student_code.value);
const name = escapeHtml(record.student_name.value);
return `
<tr>
<td>
<div class="kintoneplugin-table-td-control">
<a href="/k/${subAppId}/show#record=${id}" target="_blank">${code}</a>
</div>
</td>
<td>
<div class="kintoneplugin-table-td-control">${name}</div>
</td>
</tr>`;
})
.join('');
return `
<table class="kintoneplugin-table">
<thead>
<tr>
<th class="kintoneplugin-table-th" style="width: 250px;"><span class="title">コード</span></th>
<th class="kintoneplugin-table-th" style="width: 250px;"><span class="title">氏名</span></th>
</tr>
</thead>
<tbody>${rows}</tbody>
</table>`;
};
kintone.events.on(['app.record.detail.show', 'app.record.edit.show'], async (event) => {
const record = event.record;
const subAppId = '{生徒管理アプリID}';
// 増殖バグ回避
if (document.getElementById('student_list') !== null) {
return event;
}
const subtableSpace = kintone.app.record.getSpaceElement('student_list');
if (!subtableSpace) {
console.warn('student_list スペースフィールドが見つかりません');
return event;
}
// 生徒管理アプリからレコード情報を取得
const params = {
app: subAppId,
query: `class_code in ("${record.class_code.value}") order by student_no asc limit 500`,
fields: ['$id', 'student_code', 'student_name'],
};
try {
const resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params);
const tableHtml = generateStudentTableHtml(resp.records, subAppId);
subtableSpace.innerHTML = tableHtml;
} catch (error) {
const errmsg =
'レコード取得時にエラーが発生しました。' + (error.message ? '\n' + error.message : '');
subtableSpace.appendChild(document.createTextNode(errmsg));
}
return event;
});
})();
|
生徒の情報を表示するテーブルを生成しています。
20
21
22
23
24
25
26
27
|
// 生徒一覧テーブルの作成
const generateStudentTableHtml = (records, subAppId) => {
const rows = records
.map((record) => {
const id = escapeHtml(record.$id.value);
const code = escapeHtml(record.student_code.value);
const name = escapeHtml(record.student_name.value);
・・・
|
38
39
40
41
42
43
44
|
})
.join('');
return `
<table class="kintoneplugin-table">
<thead>
・・・
|
49
50
51
|
<tbody>${rows}</tbody>
</table>`;
};
|
レコード詳細表示およびレコード編集イベントで、生徒一覧テーブル生成処理を実行します。
53
54
|
kintone.events.on(['app.record.detail.show', 'app.record.edit.show'], async (event) => {
・・・
|
REST APIを使って、生徒管理アプリからクラス登録した生徒の情報を取得しています。
なお、queryのパラメーターには、クラスコードが一致するレコードのみを取得するように指定します。
取得するフィールドは、「レコード番号」、「生徒コード」、「生徒氏名」となります。
68
69
70
71
72
73
74
75
76
77
78
79
80
|
// 生徒管理アプリからレコード情報を取得
const params = {
app: subAppId,
query: `class_code in ("${record.class_code.value}") order by student_no asc limit 500`,
fields: ['$id', 'student_code', 'student_name'],
};
try {
const resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params);
const tableHtml = generateStudentTableHtml(resp.records, subAppId);
subtableSpace.innerHTML = tableHtml;
} catch (error) {
・・・
|
なお、クロスサイトスクリプティングの対策として、特殊文字をエスケープ処理しています。
生徒管理アプリ、クラス管理アプリそれぞれにいくつかデータを入力します。
生徒管理アプリから、いくつかクラスをルックアップで登録し、「クラスアプリ管理」上に生徒一覧のテーブルが表示されていることを確認します。
詳細データ設定用のアプリを別途作成することにより、標準機能で対応も可能です。
しかし、JavaScript APIでカスタマイズすれば、わざわざ詳細データ設定用のアプリを作成しなくて済みます。
コード自体も意外とシンプルですので、ぜひ試してみてください。