カテゴリー内の他の記事

kintone UI Component v0を使って動的ドロップダウンを作成しよう!

(著者:江田 篤史

Index

はじめに

kintone UI Componentは、kintoneライクなUIを簡単に作成できるライブラリでフォーム部品を自作する場合などには非常に便利です。

今回は選択肢を動的に変更するドロップダウンを作成してみました。

2021年3月5日追記
kintone UI Component v1 をリリースしました。使い方などの詳細は、kintone UI Component v1 をご参照ください。
この記事で利用している v0 は、メンテナンスモードに移行しています。

サンプル

アンケートなどで47都道府県から自身が該当する都道府県を直接選ぶのは大変ですよね!

選択した「地方」に合わせて、「都道府県」の選択肢を変更するカスタマイズを紹介します。

デモ

demo-1.gif

フォーム設定

フィールド名 フィールドタイプ フィールドコード(or 要素ID)
地方 ドロップダウン

地方

・項目
 - 北海道地方
 - 東北地方
 - 関東地方
 - 中部地方
 - 近畿地方
 - 中国地方
 - 四国地方
 - 九州地方

都道府県 文字列 (1行) 都道府県
- スペース space

コード

sample.jsとして後述のプログラムと、kintone-ui-component.min.js と kintone-ui-component.min.cssをアプリに適用します。

参考:JavaScriptやCSSでアプリをカスタマイズする

kintone-ui-component.min.js と kintone-ui-component.min.css の入手方法は以下のとおりです。

  1. https://github.com/kintone-labs/kintone-ui-component/releases を開きます。
  2. v0.〜で始まるバージョンの「Assets」からkintone-kintone-ui-component-0.x.tgzをダウンロードします。
    0.xはバージョン番号です。
  3. ダウンロードしたtgzファイルを解凍します。
  4. 解凍後のフォルダー package > dist 以下のkintone-ui-component.min.jskintone-ui-component.min.cssを利用します。

この記事では、kintone UI Component v0.4.3 を使用しています。
kintone UI Component アップデートにより、デモと動きが異なる可能性があります。ご了承ください。

解説

kintone UI Component を用いた、動的ドロップダウン作成の流れを解説します。

  1. ラベルとドロップダウンを作成
  2. ドロップダウンの値をレコードとして保存
  3. 選択肢を可変にする

パートごとに利用したkintone UI Componentのメソッドを書き出しておくので、メソッドの詳しい解説はこちらなどを参考にしてください。
※ここでは「都道府県」の選択肢を関東地方の都県に絞って解説していきます。

1. ラベルとドロップダウンを作成

用意したスペースフィールド内に、ラベルとドロップダウンを作成します。

コード 

利用したkintone UI Componentのメソッド

  • Label() : ラベルの作成
  • Dropdown() : ドロップダウンの作成
  • 〇〇.render():DOM要素の取得
    • 例) label.render()、dropdown.render()

デモ

demo2.gif

2. ドロップダウンの値をレコードとして保存

先ほど作成したドロップダウンの値を「文字列 (1行)」フィールドにコピーすることでレコードとして保存します。

コード 

利用したkintone UI Componentのメソッド

  • Dropdown().on() : ドロップダウンのイベントリスナの追加

デモ

demo3.gif

3. 選択肢を可変にする

選択した「地方」に合わせて、「都道府県」の選択肢を動的に変更します。コード及びデモは冒頭のサンプルを参照してください。

利用したkintone UI Componentのメソッド

  • Dropdown().setValue() : ドロップダウンの値の設定
  • Dropdown().getItems() : ドロップダウンの選択肢の取得
  • Dropdown().removeItem() : ドロップダウンの選択肢の削除
  • Dropdown().addItem() : ドロップダウンの選択肢の追加

おわりに

kintone UI Componentを使用すると、DOM等の知識がなくても容易にkintoneライクなフォーム部品を作成できるようになります。
いろいろとカスタマイズの幅が大幅に広がりますので、是非活用してみてください。

変更履歴

  • 2019年11月25日
    kintone UI Component v0.4.3 に合わせてサンプルコードおよびデモのスクショを修正しました。
    • 「都道府県」の値が選択済みのときの場合でも、「地方」を変更するときに「都道府県」の値を初期化する
    • 「都道府県」が選択されていない状態で保存した場合、エラーを表示する

関連Tips

このTipsは、2019年11月版 kintoneで確認したものになります。

記事に関するフィードバック

記事のコメント欄は記事に対するフィードバックをする場となっております。
右の記事フィードバックのためのガイドを参照してコメントしてください。
記事のリンク切れなど、気になる点がある場合も、こちらのフォームからフィードバックいただけますと幸いです。

Avatar
Kintoneに挑戦中

この機能は レコード一覧画面では動作しないのでしょうか?

どうすればレコード一覧画面で利用できるようになるのでしょうか? 教示ください。

Avatar
cybozu Development team

Kintoneに挑戦中 様

このTipsは動的ドロップダウン作成のためにスペースフィールドを利用していますが、

レコード一覧画面ではスペースフィールドを利用できないため、この方法ではできません。

別の実装方法を考える必要があります。

本記事の方法とは異なりますので、恐れ入りますが、プログラミング時のご相談はcybozu developer コミュニティのご活用をお願いいたします。

Avatar
amainodaisuki

こちらの機能についてですが、「3. 選択肢を可変にする」が現在動作しません。

1. ラベルとドロップダウンを作成
2. ドロップダウンの値をレコードとして保存

は正常に動作することが確認できました。

何か原因があるのでしょうか?

Avatar
cybozu Development team

amainodaisuki 様

お世話になっております。
cybozu developer network 事務局です。

動作確認をしたところ、kintone UI Componentの最新バージョン「v0.4.3」で正常に動作しないことが確認できました。
バージョンアップに合わせて記事を修正しましたので、再度ご確認お願いできますでしょうか。

修正箇所は以下の通りです。
「コード」部分の23行目
【修正前】
dropdown.setValue();

【修正後】
 dropdown.setValue('') ;

Avatar
Tsutsumi Ayumi

こちらを試したところ、ReferenceError : kintoneUIComponent is not defined となってしまいます。

そのままのコードを用いても同じエラーが発生してしまいます。。

どうすれば解決するでしょうか?

 

 

 

Avatar
cybozu Development team

Tsutsumi Ayumi さま

サンプルコード以外に、kintone-ui-component.min.js と kintone-ui-component.min.css も適用されてますでしょうか。

まだの場合、

https://developer.cybozu.io/hc/ja/articles/360000511023

「kintone UI Componentのダウンロード」の記載部分をお読みになり適用をお願いします。

なお、kintone-ui-component.min.js はサンプルコードよりも上に適用ください。

cssファイルはjsファイルと同画面でも適用部分がわかれているため、ご注意ください。

記載に不足があり申し訳ありません。

Avatar
Tsutsumi Ayumi

ご担当者様

ありがとうございます。解決いたしました。

少しずつ勉強させていただきたいと思います。

 

Avatar
yamagata

ご担当者様

デモでは地方の値を変更すると都道府県の値が一旦空白になっているようですが、こちらのコードでは地方を変更しても都道府県は前の値のままのようです。確認していただけますでしょうか?

よろしくお願いいたします。

 

Avatar
cybozu Development team

yamagata 様

お世話になっております。cybozu developer network 運営局です。

kintone UI Component のバージョンアップで、ドロップダウンの動作が変わっておりました。
別の「地域」が選択されたときは「都道府県」が初期化されるように、ソースコードを修正いたしました(変更履歴

  • 31行目:初期化用の選択肢を追加、26行目:「地域」が変わったときに初期化されるようにセットする処理を追加
  • 66-75行目:「都道府県」で初期化用の選択肢を選んだ場合(空文字が入力された場合)は、エラーとする処理を追加

よろしくお願いいたします。

Avatar
yamagata

ご担当者様

対応していただきまして、ありがとうございました。

Avatar
Hiroki Wakita

ご担当者様

こちらを参考にさせていただき、4階層のドロップダウンを作成したいのですが、

技術的には可能でしょうか。ポイントや注意点を教えていただけると幸いです。

お手数ですが、よろしくお願いいたします。

Avatar
cybozu Development team

Hiroki Wakita 様

お世話になっております。
cybozu developer network 運営事務局です。

>4階層のドロップダウンを作成したいのですが、

4階層のドロップダウンとは、選択肢が連動して変わる、
4つのドロップダウンを作成したいということでしょうか?

一例ですが、
標準機能のドロップダウン一つ、kintone UI Component のドロップダウン3つを作成していただき、
後者のドロップダウンの値の連動は、kintone UI Componentのドロップダウンのchangeイベントを使って行う、
という処理であれば、技術的に可能だと思います。

また、こちらは記事に対するフィードバックの欄となっておりますため、
記事の内容の発展などのご質問は、大変お手数ですがコミュニティにお願いできますでしょうか。
コミュニティのほうが多くの方がご覧になっているため、アドバイスも得やすいかと思います。

よろしくお願いいたします。

Avatar
Hiroki Wakita

ご担当者様

一例としての回答をいただき有難うございます。

今回の例のような質問については、コミュニティへの質問との事で承知いたしました。

以後気をつけます。

 

Avatar
FJP

ご担当者様

動的ドロップダウンを2階層(大カテゴリーと小カテゴリー)で作成したいのですが、

小カテゴリーにつきまして、複数選択の設定は可能でしょうか?

ご確認いただければ幸いです。どうぞよろしくお願いいたします。

Avatar
cybozu Development team
FJP 様
 
お世話になっております。cybozu developer network 運営事務局です。
 
ドロップダウンのコンポーネントは、選択できるのは一つまでとなっております。
複数選択したい場合は、複数選択のコンポーネントもありますのでご検討ください。
 
また、こちらのコメント欄は、記事通りに試したが動かない等の記事へのフィードバック用となります。
上記試してみてわからないなどあれば、ぜひコミュニティをご活用ください。
https://developer.cybozu.io/hc/ja/community/topics
Avatar
古澤 克彦

ご担当者様

 

お世話になります。

上記の動的ドロップダウンを参考に、アプリを作成中です。

しかし、動的ドロップダウンを複数作成すると、思うように配置ができません。

spaceの配置によっては、縦に並びレイアウトがひどい状態になります。

可能であれば、ドロップダウンの横に、文字列一行を配置。

その下の行に、同様の配置をしたいと考えています。

ドロップダウン配置の制御方法を、ご教示願います。

お手数をお掛けしますが、宜しくお願いします。

Avatar
cybozu Development team

古澤 克彦さま

お世話になっております。cybozu developer network 運営事務局です。
 
基本的には動的なドロップダウンを複数利用しても、当記事冒頭にある画像のように表示することは可能です。
 
カスタマイズの状況・仕方によっては、他のライブラリとの兼ね合いやコードの書き方などで不具合が発生することはあるかもしれませんが、
こちらのコメント欄は、記事通りに試したが動かない等の記事へのフィードバック用となります。
 
恐れ入りますが、技術的な疑問などは、ぜひコミュニティをご活用ください。
Avatar
湊くん

ご担当者様

お世話になります

一つの質問があります。

逆に都道府県のあたいを入力したら、一番該当するドロップダウンの値が設定できますか、

例えば:都道府県を「東京」入力したら、ドロップダウンの値が「東京」を自動的に選択されています可能でしょうか

ご回答をお待ちしております。

湊くんにより編集されました
Avatar
cybozu Development team

湊くん様

お世話になっております。cybozu developer network 運営局です。

kintone UI Component では、Text フィールドに change イベントがあるので可能かと思われます。
https://kintone.github.io/kintone-ui-component/latest/Reference/Text/#oneventname-callback

なお、こちらは記事の内容に対するフィードバックとなっております。
記事に記載している内容以上のことについては、コミュニティをご活用ください。

Avatar
湊くん

ご担当者様 「昨日 17:07」/2020/12/16

参考してから、正常に動作することが確認できました。

誠にありがとうございます。

Avatar
chu thi hue

お世話になっております。

こちらを試したところ、Uncaught TypeError: Cannot read property 'appendChild' of null となってしまいます。

そのままのコードを用いても同じエラーが発生してしまいます。。

どうすれば解決するでしょうか?

Avatar
cybozu Development team

chu thi hue 様

お世話になっております、cybozu developer network 事務局です。

もし不都合がないようでしたら、新バージョンの kintone UI Component v1 の利用をおすすめいたします。

また、動作に関する疑問点などは、ぜひコミュニティをご活用ください。

Avatar
chu thi hue

お世話になっております。

こちらを試したところ,作成する際、や、編集する際にしかフィールドが表示されていません。

尚、データを保存するのはまだできていません。

ビデオを取っておりました。ご確認のほどよろしくお願いいたします。

以下はソースコードです。

var originAppId = 14;
var dataMaster = [];

(function() {
'use strict';

kintone.events.on(['app.record.create.show', 'app.record.edit.show'], function(event) {
console.log('vaoooo');
var pararams = {
"app": originAppId,
"query": "order by 表示順 asc"
}

return kintone.api('/k/v1/records', 'GET', pararams).then(function(resp) {
if (resp['records'].length == 0) return;

resp['records'].forEach(function(item) {
if (dataMaster[item['組織']['value']] === undefined) {
dataMaster[item['組織']['value']] = [];
}

if (dataMaster[item['組織']['value']]['区分'] == undefined) {
dataMaster[item['組織']['value']]['区分'] = [];
}

if (dataMaster[item['組織']['value']]['TGL'] == undefined) {
dataMaster[item['組織']['value']]['TGL'] = [];
}

if (dataMaster[item['組織']['value']]['区分'].length == 0) {
dataMaster[item['組織']['value']]['区分'].push([item['区分']['value']]);
} else {
var exitsItem = false;
for (let i = 0; i < dataMaster[item['組織']['value']]['区分'].length; i++) {
if (dataMaster[item['組織']['value']]['区分'][i] == item['区分']['value']) {
exitsItem = true;
break;
}
}

if (!exitsItem) {
dataMaster[item['組織']['value']]['区分'].push([item['区分']['value']]);
}
}

if (dataMaster[item['組織']['value']]['TGL'].length == 0) {
dataMaster[item['組織']['value']]['TGL'].push([item['TGL']['value']]);
} else {
var exitsItem = false;
for (let i = 0; i < dataMaster[item['組織']['value']]['TGL'].length; i++) {
if (dataMaster[item['組織']['value']]['TGL'][i] == item['TGL']['value']) {
exitsItem = true;
break;
}
}

if (!exitsItem) {
dataMaster[item['組織']['value']]['TGL'].push([item['TGL']['value']]);
}
}
});
})
.then (function () {
var parentDropdown = createDropdown('space1', '所属', true);
var tglDropdown = createDropdown('space2', '折衝先', false, '', 'TGL');
var kubunDropdown = createDropdown('space3', '区分', false, '', '区分');

parentDropdown.on('change', function(parentValue) {
removeDropdownItems(tglDropdown);
removeDropdownItems(kubunDropdown);

setDropdownItems(tglDropdown, parentValue, 'TGL');
setDropdownItems(kubunDropdown, parentValue, '区分');

var record = kintone.app.record.get();
console.log('==== record ===');
console.log(record);

// record.record.所属.value = parentValue;
// record.record.折衝先.value = '西江東';
// record.record.区分.value = 'EF';

kintone.app.record.set(record);
});
})
.catch(function(error) {
var errmsg = 'There was an error occurred';
if (error.message !== undefined){
errmsg += '\n' + error.message;
}
console.log(errmsg);
alert(errmsg);
});
});

// kintone.events.on(['app.record.create.submit', 'app.record.edit.submit'], function(event) {
// var record = event.record;
// if (!record.所属.value) {
// event.error = '所属を選択してください';
// }
// return event;
// });
})();

function createDropdown(space, fieldCode, isParent = false, parent = '', child = '', defaultValue = '') {
var options = [];

if (isParent) {
for(var key in dataMaster) {
var option = { label: key, value: key };
options.push(option);
}

} else {
if (dataMaster[parent] !== undefined) {
dataMaster[parent][child].forEach( function(item) {
var option = { label: item, value: item };
options.push(option);
});
}
}

var label = new kintoneUIComponent.Label({text: fieldCode});
var dropdown = new kintoneUIComponent.Dropdown({items: options});

kintone.app.record.setFieldShown(fieldCode, true);
kintone.app.record.getSpaceElement(space).appendChild(label.render());
kintone.app.record.getSpaceElement(space).appendChild(dropdown.render());

dropdown.setValue(defaultValue);

return dropdown;
}

function removeDropdownItems(dropdown) {
dropdown.setValue('');
while (dropdown.getItems().length) {
dropdown.removeItem(0);
}
}

function setDropdownItems(dropdown, parent, child) {
// dropdown.addItem({label: '-----', value: ''});

if (dataMaster[parent][child].length > 0) {
dataMaster[parent][child].forEach(function(item) {
dropdown.addItem({
label: item,
value: item
});
});
dropdown.setValue('');
}
}

 
Avatar
cybozu Development team

chu thi hue 様

お世話になっております、cybozu developer network 事務局です。

恐れ入りますが、こちらのコメント欄は記事内容についてのフィードバック目的となっております。
個別の事象や技術的なご質問は、cybozu developer コミュニティをご活用ください。

お手数ですが、ご確認のほどよろしくお願いいたします。

Avatar
のぶお

お世話になっています。

こちらを試しているのですが、dropdown.setValue('') ; のところで

TypeError: Cannot read property 'setValue' of undefined のエラーが出て上手く機能しません。

対応方法を教えてください。

サインインしてコメントを残してください。