ドロップダウンによる検索

投稿失礼します。

現在他の方のを参考に一覧画面での検索をしたいと考えています。

参考にしているコードは”input”で直接入力になっておりますが、この部分を"select"に変更してドロップダウンで検索したいと考えています。

以下、該当のコード部分です。

var search_word1 = document.createElement(‘select’); //←この部分がinputです。

// 取得したレコードに設定されたフィールド値をoptionをに設定する

var field1 = record[‘項目’].value;

var option1 = document.createElement(‘option’); // option作成

option1.setAttribute(‘value’, field1); // optionのvalueを設定

option1.innerHTML = field1; // optionの表示名を設定

select.appendChild(option1); // selectにoptionを設定

 

オプションを設定すると、他の検索窓も表示されなくなってしまう状態です。

どなたかわかる方見えましたらご教授願いたいです。

よろしくお願いします。

H_ishi様

 

内容拝見いたしました。

コードの全貌やエラー箇所がわからないため、正確なことが申し上げられませんが、記載の内容だけで考えると、

 

select.appendChild(option1); // selectにoptionを設定

 

で落ちているのではないかと思います。

select という変数はどこにも宣言されていないからです。

search_word1という変数にセレクトボックスを格納しているようですので、

 

search_word1.appendChild(option1);

 

と書き換えてみると動くのではないでしょうか。

もし違う場合、他の部分の影響かもしれませんので、改めて全コードを補記して頂けると、原因が特定しやすいかと思います。

大西 佑太様

ご教授ありがとうございます。返信が遅くなってしまい申し訳ありません。

指摘頂いた箇所を訂正しましたが、動作に変わりありませんでした。

以下コード全文を記載します。お時間の許す際に拝見して頂けたらと思います。

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

// 設定値

const FIELD_CODE1 = “項目”;

const FIELD_CODE1_NAME = “項目”;

const AND_OR = “and”; // 必ず小文字

const FIELD_CODE2 = “点数”;

const FIELD_CODE2_NAME = “点数”;

// 一覧表示のタイミングで実行

(function () {

“use strict”;

kintone.events.on(“app.record.index.show”, function (event) {

// GET引数に格納された直前の検索キーワードを取得して再表示する

varresult= {};

varquery=window.location.search.substring( 7 ); // URL固定部分(?query=)は無視

// クエリ検索条件の区切り記号 (and/or) で分割

varparameters=query.split( AND_OR );

// フィールドコード名と検索キーワードに分割する

for( vari=0; i<parameters.length; i++ ){

varelement=parameters[i].split( ‘like’ );

varparamName=decodeURIComponent( element[0] );

varparamValue=decodeURIComponent( element[1] );

 

// スペースと""をtrimして、文字列だけにしてから、配列に格納

result[paramName.replace(/^\s+|\s+$/g, “”)] =paramValue.replace(/^[\s|"]+|[\s|"]+$/g, “”);

}

// 検索キーワードその1

varsearch_word1=document.createElement(‘select’);

search_word1.onkeypress=function(e) {

if (e.keyCode&&e.keyCode==13) {

keyword_search();

}

}

if(result[FIELD_CODE1] !=undefined){

search_word1.value=result[FIELD_CODE1]; // GET引数に、直前の検索キーワードがあったら格納しておく

}

// 取得したレコードに設定されたフィールド値をoptionをに設定する

var field1 = record[‘項目’].value;

var option1 = document.createElement(‘option’); // option作成

option1.setAttribute(‘value’, field1); // optionのvalueを設定

option1.innerHTML = field1; // optionの表示名を設定

search_word1.appendChild(option1); // selectにoptionを設定

 

// 検索キーワードその2

varsearch_word2=document.createElement(‘select’);

search_word2.onkeypress=function(e) {

if (e.keyCode&&e.keyCode==13) {

keyword_search();

}

}

if(result[FIELD_CODE2] !=undefined){

search_word2.value=result[FIELD_CODE2]; // GET引数に、直前の検索キーワードがあったら格納しておく

}

 

// 取得したレコードに設定されたフィールド値をoptionをに設定する

var field2 = record[‘点数’].value;

var option2 = document.createElement(‘option’); // option作成

option2.setAttribute(‘value’, field2); // optionのvalueを設定

option2.innerHTML = field2; // optionの表示名を設定

search_word1.appendChild(option2); // selectにoptionを設定

// 検索ボタン

varsearch_button=document.createElement(‘button’);

search_button.innerHTML=‘検索’;

search_button.onclick=function () {

keyword_search();

};

 

// キーワード検索の関数

functionkeyword_search(){

varkeyword1=search_word1.value;

varkeyword2=search_word2.value;

varstr_query=‘?query=’+FIELD_CODE1+’ like “‘+keyword1+’” ’

+AND_OR+’ ‘+FIELD_CODE2+’ >= “‘+keyword2+’”';

 

if(keyword1==“”&&keyword2==“”){

str_query=“”;

}else if(keyword1 != “” && keyword2 == “”){

str_query=‘?query=’+FIELD_CODE1+’ like “‘+keyword1+’”’

}else if(keyword1 == “” && keyword2 != “”){

str_query=‘?query=’+FIELD_CODE2+’ >= “‘+keyword2+’”’

}

 

// GET変数を使って、検索結果へジャンプ!

document.location=location.origin+location.pathname+str_query

}

// キーワード入力部品を、kintoneヘッダ部分に埋め込む(重複を避けるため、最初に要素をクリアしておく)

varaNode=kintone.app.getHeaderMenuSpaceElement()

 

for (vari=aNode.childNodes.length-1; i>=0; i–) {

aNode.removeChild(aNode.childNodes[i]);

}

// 検索窓の表示ラベル設定

varlabel=document.createElement(‘label’);

label.appendChild(document.createTextNode(FIELD_CODE1_NAME));

label.appendChild(search_word1);

label.appendChild(document.createTextNode(FIELD_CODE2_NAME));

label.appendChild(search_word2);

label.appendChild(document.createTextNode(’ '));

label.appendChild(search_button);

kintone.app.getHeaderMenuSpaceElement().appendChild(label);

returnevent;

});

})();

H_ishi様

コード拝見いたしました。

 

本当にこれが実装されているコードの全文だとすると、

 

varparameters=query.split( AND_OR );

 

で落ちるはずです。

 

varresult= {};

や、

varquery=window.location.search.substring( 7 );

 

のように、変数宣言のvarと変数名を詰めて書いているため、「varresult」や「varquery」という名前のグローバル変数として定義されていて、queryという変数は存在しないためです。

 

下記の記事をご参照頂き、正確なコードに直してみてください。

 

・デバッグのやり方

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

・JavaScript入門

https://www.javadrive.jp/javascript/

 

もしスペースの詰まりが意図的なものではないのであれば、正確なコードを貼り付けてください。

大西 佑太様

お手数をお掛けして申し訳ありません。

コードはコピペした際にスペースが詰められており、こちらの意図してものではありませんでした。

申し訳ありません。

以下、コード全文です。

// 設定値

const FIELD_CODE1 = “項目”;

const FIELD_CODE1_NAME = “項目”;

const AND_OR = “and”; // 必ず小文字

const FIELD_CODE2 = “点数”;

const FIELD_CODE2_NAME = “点数”;

// 一覧表示のタイミングで実行

(function () {

“use strict”;

kintone.events.on(“app.record.index.show”, function (event) {

// GET引数に格納された直前の検索キーワードを取得して再表示する

var result= {};

var query=window.location.search.substring( 7 ); // URL固定部分(?query=)は無視

// クエリ検索条件の区切り記号 (and/or) で分割

var parameters=query.split( AND_OR );

// フィールドコード名と検索キーワードに分割する

for( var i =0; i<parameters.length; i++ ){

var element=parameters[i].split( ‘like’ );

var paramName=decodeURIComponent( element[0] );

var paramValue=decodeURIComponent( element[1] );

 

// スペースと""をtrimして、文字列だけにしてから、配列に格納

result[paramName.replace(/^\s+|\s+$/g, “”)] =paramValue.replace(/^[\s|"]+|[\s|"]+$/g, “”);

}

// 検索キーワードその1

var search_word1=document.createElement(‘select’);

search_word1.onkeypress=function(e) {

if (e.keyCode&&e.keyCode==13) {

keyword_search();

}

}

if(result[FIELD_CODE1] !=undefined){

search_word1.value=result[FIELD_CODE1]; // GET引数に、直前の検索キーワードがあったら格納しておく

}

// 取得したレコードに設定されたフィールド値をoptionをに設定する

var field1 = record[‘項目’].value;

var option1 = document.createElement(‘option’); // option作成

option1.setAttribute(‘value’, field1); // optionのvalueを設定

option1.innerHTML = field1; // optionの表示名を設定

search_word1.appendChild(option1); // selectにoptionを設定

 

// 検索キーワードその2

var search_word2=document.createElement(‘select’);

search_word2.onkeypress=function(e) {

if (e.keyCode&&e.keyCode==13) {

keyword_search();

}

}

if(result[FIELD_CODE2] !=undefined){

search_word2.value=result[FIELD_CODE2]; // GET引数に、直前の検索キーワードがあったら格納しておく

}

 

// 取得したレコードに設定されたフィールド値をoptionをに設定する

var field2 = record[‘点数’].value;

var option2 = document.createElement(‘option’); // option作成

option2.setAttribute(‘value’, field2); // optionのvalueを設定

option2.innerHTML = field2; // optionの表示名を設定

search_word1.appendChild(option2); // selectにoptionを設定

// 検索ボタン

var search_button=document.createElement(‘button’);

search_button.innerHTML=‘検索’;

search_button.onclick=function () {

keyword_search();

};

 

// キーワード検索の関数

function keyword_search(){

var keyword1=search_word1.value;

var keyword2=search_word2.value;

var str_query=‘?query=’+FIELD_CODE1+’ like “‘+keyword1+’” ’

+AND_OR+’ ‘+FIELD_CODE2+’ >= “‘+keyword2+’”';

 

if(keyword1==“”&&keyword2==“”){

str_query=“”;

}else if(keyword1 != “” && keyword2 == “”){

str_query=‘?query=’+FIELD_CODE1+’ like “‘+keyword1+’”’

}else if(keyword1 == “” && keyword2 != “”){

str_query=‘?query=’+FIELD_CODE2+’ >= “‘+keyword2+’”’

}

 

// GET変数を使って、検索結果へジャンプ!

document.location=location.origin+location.pathname+str_query

}

// キーワード入力部品を、kintoneヘッダ部分に埋め込む(重複を避けるため、最初に要素をクリアしておく)

varaNode=kintone.app.getHeaderMenuSpaceElement()

 

for (var i=aNode.childNodes.length-1; i>=0; i–) {

aNode.removeChild(aNode.childNodes[i]);

}

// 検索窓の表示ラベル設定

var label=document.createElement(‘label’);

label.appendChild(document.createTextNode(FIELD_CODE1_NAME));

label.appendChild(search_word1);

label.appendChild(document.createTextNode(FIELD_CODE2_NAME));

label.appendChild(search_word2);

label.appendChild(document.createTextNode(’ '));

label.appendChild(search_button);

kintone.app.getHeaderMenuSpaceElement().appendChild(label);

return event;

});

})();

H_ishi様

 

コード拝読いたしました。

 

var aNodeがまだ詰まっていましたが、一旦無視しました。

(私の氏名の漢字も二度間違っているようです。コーディングをする際、タイプミスには必ず注意してください。)

 

var field1 = record[FIELD_CODE1].value;

 

という記述がありますが、recordという変数は定義していません。

そのため、そこで処理が落ちます。

 

例えば、event.recordsで一覧に表示されているレコードの配列を取得し、それをループする方法があります。

 

また、option2をappendする先がsearch_word1になっていました。search_word2が正しい変数です。

また、ドロップダウンで検索する際のクエリは「like」ではなく「in」です。

https://developer.cybozu.io/hc/ja/articles/202331474#step2

また、select要素に対するonkeypressイベントは有効ではないので、問題はありませんが削除していいでしょう。

 

修正したコードを以下に記載します。

このコードには下記の課題があります。解法を考えてみてください。

 

・クエリ文字列からlikeで分割して直前の検索ワードを持ってくることができないので、inに変更し、トリム方法も修正する必要がある

・一覧に表示されているレコード群に、同じ選択肢が登録されたレコードが複数ある場合、重複した数だけ同じ選択肢がセレクトボックス内に出るため、optionの追加処理部分で重複削除処理が必要になる

 


 

// 設定値
const FIELD_CODE1 = “項目”;
const FIELD_CODE1_NAME = “項目”;
const AND_OR = “and”; // 必ず小文字
const FIELD_CODE2 = “点数”;
const FIELD_CODE2_NAME = “点数”;

// 一覧表示のタイミングで実行
(function () {
    “use strict”;
    kintone.events.on(“app.record.index.show”, function (event) {
        var records = event.records;

        // GET引数に格納された直前の検索キーワードを取得して再表示する
        var result = {};
        var query = window.location.search.substring(7); // URL固定部分(?query=)は無視

        // クエリ検索条件の区切り記号 (and/or) で分割
        var parameters = query.split(AND_OR);

        // フィールドコード名と検索キーワードに分割する
        for(var i = 0; i < parameters.length; i++) {
            var element = parameters[i].split(‘like’);
            var paramName = decodeURIComponent(element[0]);
            var paramValue = decodeURIComponent(element[1]);

            // スペースと""をtrimして、文字列だけにしてから、配列に格納
            result[paramName.replace(/^\s+|\s+$/g, “”)] = paramValue.replace(/^[\s|"]+|[\s|"]+$/g, “”);
        }

        // 検索キーワードその1
        var search_word1 = document.createElement(‘select’);

        if(result[FIELD_CODE1] != undefined){
            search_word1.value = result[FIELD_CODE1]; // GET引数に、直前の検索キーワードがあったら格納しておく
        }

        // 一覧に表示されているレコード数分ループし、Optionを追加する
        for(var i = 0; i < records.length; i++) {
            var record = records[i];
            // 取得したレコードに設定されたフィールド値をoptionをに設定する
            var field1 = record[FIELD_CODE1].value;
            var option1 = document.createElement(‘option’); // option作成
            option1.setAttribute(‘value’, field1); // optionのvalueを設定
            option1.innerHTML = field1; // optionの表示名を設定
            search_word1.appendChild(option1); // selectにoptionを設定
        }

        // 検索キーワードその2
        var search_word2 = document.createElement(‘select’);

        if(result[FIELD_CODE2] != undefined){
            search_word2.value = result[FIELD_CODE2]; // GET引数に、直前の検索キーワードがあったら格納しておく
        }

        // 一覧に表示されているレコード数分ループし、Optionを追加する
        for(var i = 0; i < records.length; i++) {
            var record = records[i];
            // 取得したレコードに設定されたフィールド値をoptionをに設定する
            var field2 = record[FIELD_CODE2].value;
            var option2 = document.createElement(‘option’); // option作成
            option2.setAttribute(‘value’, field2); // optionのvalueを設定
            option2.innerHTML = field2; // optionの表示名を設定
            search_word2.appendChild(option2); // selectにoptionを設定
        }

        // 検索ボタン
        var search_button = document.createElement(‘button’);
        search_button.innerHTML = ‘検索’;
        search_button.onclick = function () {
            keyword_search();
        };

        // キーワード検索の関数
        function keyword_search(){
            var keyword1 = search_word1.value;
            var keyword2 = search_word2.value;
            var str_query = ‘?query=’ + FIELD_CODE1 + ’ in (“’ + keyword1 + '”) ’ + AND_OR + ’ ’ + FIELD_CODE2 + ’ in (“’ + keyword2 + '”)';

            if(keyword1 == “” && keyword2 == “”) {
                str_query = “”;
            } else if (keyword1 != “” && keyword2 == “”) {
                str_query = ‘?query=’ + FIELD_CODE1 + ’ in (“’ + keyword1 + '”)‘;
            } else if (keyword1 == “” && keyword2 != “”) {
                str_query = ‘?query=’ + FIELD_CODE2 + ’ in ("’ + keyword2 + ‘")’;
            }

            // GET変数を使って、検索結果へジャンプ!
            document.location = location.origin + location.pathname + str_query;
        }

        // キーワード入力部品を、kintoneヘッダ部分に埋め込む(重複を避けるため、最初に要素をクリアしておく)
        var aNode = kintone.app.getHeaderMenuSpaceElement();

        for (var i = aNode.childNodes.length - 1; i >= 0; i–) {
            aNode.removeChild(aNode.childNodes[i]);
        }
        // 検索窓の表示ラベル設定
        var label = document.createElement(‘label’);
        label.appendChild(document.createTextNode(FIELD_CODE1_NAME));
        label.appendChild(search_word1);
        label.appendChild(document.createTextNode(FIELD_CODE2_NAME));
        label.appendChild(search_word2);
        label.appendChild(document.createTextNode(’ '));
        label.appendChild(search_button);
        kintone.app.getHeaderMenuSpaceElement().appendChild(label);

        return event;
    });
})();

ちなみに、kintoneアプリ上で「項目」や「点数」がドロップダウンではなく、文字列(1行)や数値なのだとすれば、URLのクエリはlikeや>=で問題ありません。これはご質問内容から読み取れなかったため、推測での修正です。

大西 佑汰様

氏名まで間違えており、大変申し訳ありませんでした。

以後、タイプミスが無いよう気を付けます。ご指摘ありがとうございました。

 

修正して頂いたコードの課題ですが、likeをinに変更し、トリム方法も修正とありましたが、

inに変更してだけでドロップダウンに変わっているかと思いますが、この状態だと問題があるという事でしょうか?

正直なところ、直前の検索ワードを持ってくるや、分割するといった部分が理解できておらず、参考にした元コードのままのところがあります。

 

次に、重複削除処理ですが、

option1.filter(function(value,index,array){

return array.indexOf( value ) === index;})

 

filterメソッドかと思いましたが、上記コードでは動作しませんでした。

見当違いな事をしておりましたら、申し訳ありません。

 

よろしくお願いします。

 

H_ishi様

 

検索ワードを持ってくる部分については、JavaScriptのメソッド単位に分解(window.location, .search, .substring())してGoogle検索などで調べて頂き、勉強してみてください。元コードのコメントも充実しているので、よく読めば何をしているのかわかるはずです。

 

kintoneの仕様として、like句でのクエリ指定とinでのクエリ指定は、その先の書き方も異なります。

つまり、likeでsplitした場合とinでsplitした場合では、得られる文字列のフォーマットが異なります。

この辺りの記事を見るとわかりやすいかと思います。

https://developer.cybozu.io/hc/ja/articles/202331474#step2

 

また、記載頂いた重複処理のコードですが、option1は配列ではなくHTML Element系の型になるので、filterは使えないはずです。

filterを使う場合、select要素のchildrenをArray.from()などで配列にしてからfilterを行い、返ってきたoption要素の配列を再度select要素の子要素に設定するような流れになるかと思います。

 

もちろん、for文でoption要素を生成する前に、recordsから取り出した値を直接処理し、処理が終わった後の配列を元にfor文でoptionを生成する方法もあります。

 

おそらくですが、まずはJavaScriptの基本的な文法やメソッドについてご理解を深める方が、本件についてもかえって近道なのではないかと思います。

大西 佑汰様

いろいろとご教授を頂きましたが、自分の勉強不足を痛感いたしました。

もう少し学んでから、もう一度この問題に取り組みたいと思います。

一旦この質問は終えさせて頂きますが、JavaScriptの理解を深めてからまた質問させて頂く事もあるかと思いますので、

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