質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Underscore.js

Underscore.jsは、JavaScriptのためのユーティリティライブラリです。JavaScriptの関数・配列、オブジェクトを扱う際に度々発生する処理がメソッドとしてまとめられています。他のライブラリに依存しないため、稼働中のアプリケーションにも導入可能です。

Q&A

解決済

2回答

1767閲覧

Underscore.jsにおける絞り込み検索について

hanayona

総合スコア9

Underscore.js

Underscore.jsは、JavaScriptのためのユーティリティライブラリです。JavaScriptの関数・配列、オブジェクトを扱う際に度々発生する処理がメソッドとしてまとめられています。他のライブラリに依存しないため、稼働中のアプリケーションにも導入可能です。

0グッド

1クリップ

投稿2018/08/28 03:43

前提・実現したいこと

Underscore.jsとjsonを使った検索機能付きのサイトを作成中です。

下記のサイトを参考にさレクトボックスでの実装は出来たのですが、
これをマルチのセレクトボックスで複数選択し検索したいのですが、
何分未熟なものでどうしてもうまくいきません。

"color"のredとblueを含む値を取得して検索するなど。

どなたかご教授頂ける方がいらっしゃいましたらお伺できますでしょうか?
何卒よろしくお願いいたします。

https://www.tam-tam.co.jp/tipsnote/javascript/post10620.html

<form id="search" name="search"> 色 <select name="color" id="color"> <option value="">指定しない</option> <option value="red">赤</option> <option value="blue">青</option> <option value="green">緑</option> </select>


<select name="type" id="type">
<option value="">指定しない</option>
<option value="square">四角</option>
<option value="circle"></option>
</select>

<input type="submit" value="検索"> </form> <div id="items"></div>

var items = [
{
"name" : "赤い四角",
"color" : "red",
"type" : "square"
},
{
"name" : "赤い丸",
"color" : "red",
"type" : "circle"
},
{
"name" : "青い四角",
"color" : "blue",
"type" : "square"
},
{
"name" : "青い丸",
"color" : "blue",
"type" : "circle"
},
{
"name" : "緑の四角",
"color" : "green",
"type" : "square"
},
{
"name" : "緑の丸",
"color" : "green",
"type" : "circle"
}
];

// 検索が押された時の処理
$('#search').on('submit' , function(event){
// デフォルトのイベントをキャンセル
event.preventDefault();

// 検索項目のオブジェクトを作成してセレクトボックスの値を格納
var query = {};
if($('#color').val() != ''){
query.color = $('#color').val();
}
if($('#type').val() != ''){
query.type = $('#type').val();
}

// データの中から一致するオブジェクトを検索
var results = _.where(items, query);

// 返ってきた配列で出力処理
outputResults(results);
});

// 検索結果の出力処理
function outputResults(results){
// 変数の初期化
var html = '';

// 受け取った配列をループで処理 // 出力するHTMLの整形 jQuery.each(results, function() { html += '<div class="item ' + this.color + ' ' + this.type + '">'; html += this.name; html += '</div>'; }); // HTMLに出力 $('#items').empty().append(html);

}

// ページ読み込み時はすべてのアイテムを出力する
$(window).on('load', function(){
outputResults(items);
});

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こんにちは。

まず前提として、lodashwhere は以下

https://github.com/lodash/lodash/wiki/Deprecations

に記載されているように、 v4 から削除されており、替わりに filter を使うことになっていますので、以下の回答もこれに従っています。

ご質問では

マルチのセレクトボックスで複数選択し検索したい

とのことですが、その場合は filter の第2引数に、条件にマッチするかどうかにより true または false を返す関数を与えれば実現できます。
具体的な修正案の一例を以下に挙げます。単一選択の場合はご質問にあるコードと同様に、

javascript

1 // データの中から一致するオブジェクトを検索 2 var results = _.filter(items, query);

とするところを、以下のように修正すればよいかと思います。

javascript

1 // データの中から一致するオブジェクトを検索 2 var results = _.filter(items, function(item) { 3 return ( 4 (query.colors.includes("") || query.colors.includes(item.color)) && 5 (query.types.includes("") || query.types.includes(item.type)) 6 ); 7 });
  • selectが複数選択可能な場合、.val() は選択された <option>の value を要素とする配列になります。

  • したがって、<select>の id と、 query のプロパティ名であるcolortypeは、colors および、types と複数形にしたほうがよいです。

  • query.colorsquery.types に対して、includes を使って、全item の中で条件を満たすものについて true を返すような関数を、filter の第2引数に渡します。

以下に上記のサンプルを作成しました。(使用している lodash のバージョンは、4.17.10です)

   

以上参考になれば幸いです。


追記

さはさりながら、_.filter の第2引数に関数を渡すのであれば、そもそも JavaScriptの標準のArray.prototype.filter() を使って以下のように書けます。この場合は lodashは不要になります。

javascript

1 // データの中から一致するオブジェクトを検索 2 var results = items.filter(function(item) { 3 return ( 4 (query.colors.includes("") || query.colors.includes(item.color)) && 5 (query.types.includes("") || query.types.includes(item.type)) 6 ); 7 });

追記2

複数選択可能な場合、colorsおよびtypesと、複数形にしたほうがよい点を回答に加筆しました。


追記3

コメントのほうで頂いた、

“指定しない”と他の選択肢を連動させることは可能でしょうか?

との件ですが、<select> の中にある、どの<option>が選ばれているかが変化したときの chageイベントハンドラに、ご要望の処理を設定することで可能です。

具体的には例えば以下を追加します。

javascript

1 // ”指定しない" が選択されたら、他の選択肢は選ばれていない状態にする 2 $('select').on('change', function() { 3 if ($(this).val().includes("")) 4 $(this).val([""]); 5 });

上記を追加すると、以下のような効果があります。

例えば、が選ばれている状態で、さらに 選択しないを選択状態にすることを想定します。すると上記で設定したchangeハンドラ function() { … } が呼ばれて、関数の中で$(this).val()とすると、選択された option の valueの配列が取れるので、今想定している状況では、["", "red", "grren"] と、3つの要素を持ちますが、これらの要素のうち、空文字列 "" が含まれているということは(= .includes("") が true ならば)、「指定しない」が選ばれたことを示しています。その場合は、「指定しない」だけが選ばれていることを表す配列 [""] を、$(this).val(設定値) に与えると、「指定しない」ではない他の選択肢は選ばれていない状態にすることができます。

※以下にサンプルを作成しました。

https://jsfiddle.net/jun68ykt/qw64naub/81/


追記4

コメントのほうから、

何度もすみません、もし可能でしたら
・・・

ということで頂戴した、追加要件を実現する方法です。

ご希望の挙動を満たすには、changeイベントが発生したときに選択状態にした<option>の value配列を保存しておいて、次に新たなchangeイベントが発生したときに選択されている<option>の value配列と、保存しておいた前回のchangeイベント発生時に選択状態にした値の配列とを比較して、次の望ましい状態を作ってから、再度、保存しておく処理が必要になると思います。どこに保存しておくかですが、 data-属性に保存するというのが一案です。

上記の比較によって判断するべき条件は、

  • 前回のchangeイベント発生時に、最終的に選択状態にした値の配列が、[""]であるか否か

です。以下は上記の実装例です。前回の選択値が[""]であるかどうかの判定のために、 lodash の isEqual を使用しています。

javascript

1 // optionの選択状態が変更されたときの設定 2 $('select') 3 .data('prev-values', [""]) 4 .on('change', function() { 5 if ($(this).val().includes("")) { 6 if (_.isEqual($(this).data('prev-values'), [""])) { 7 $(this).val($(this).val().filter(v => v!="")); 8 } else { 9 $(this).val([""]); 10 } 11 } 12 $(this).data('prev-values', [...$(this).val()]); 13 });

上記のサンプルを

https://jsfiddle.net/jun68ykt/qw64naub/95/

に作成しました。


追記5

「onChangeハンドラの中で、対象のchangeイベントが発生する前の value を取得するにはどうしたらいいか?」というお題は、以下にも投稿されています。

stackoverflow: Getting value of select (dropdown) before change

上記の回答の中にも、changeイベントが発生して選択された値を保存しておく場所として、 data-属性を使うというものが、いくつか見つかります。


追記6

追記4 に書いたコードの以下の部分

javascript

1$(this).val($(this).val().filter(v => v!=""));

は、以下のように書くことで少し短くすることができます。

javascript

1$(this).val($(this).val().filter(v => v));

投稿2018/08/28 11:40

編集2018/09/01 00:19
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hanayona

2018/08/29 09:34

おっしゃる通りに出来ました、ありがとうございます! 丁寧なご説明で色々勉強になりました!! ほんと助かりました!
jun68ykt

2018/08/29 10:34

解決されたようですね、よかったです!
hanayona

2018/08/30 07:10

何度も済みません。 ほんと、もし可能だったらですが、“指定しない”と他の選択肢を連動させることは可能でしょうか? 例えば ”“指定しない”を選ぶと赤、青、緑の選択が外れ、逆に赤を選択した後に”“指定しない”を選ぶと赤の選択が外れるような。 ”“指定しない”と他の赤、青、緑のどれかが一緒になることを避けたいのですが。 そんな夢のようなことが、もし可能でしたらお教えいただけると助かります。
jun68ykt

2018/08/30 08:03

こんにちは。回答の追記3 のほうで返答しましたのでご確認ください。
jun68ykt

2018/08/30 08:11

初期表示と select の状態を合わせるために、 「指定しない」の <option> に selected 属性を追加したほうがよいと思いました。これを追加したものが、 https://jsfiddle.net/jun68ykt/qw64naub/81/ です。
hanayona

2018/08/30 09:12

早速のご返答誠にありがとうございます! 旨く設置ができました! まさにやりたかったことをご指南いただきめちゃくちゃ感謝です! 本当にありがとうございます!!!
hanayona

2018/08/31 06:57

何度もすみません、もし可能でしたら 〉赤 と緑が選ばれている状態で、さらに 選択しないを選択状態にする 時に加えて、 既に“選択しない”のみが選ばれている状態で、さらに 赤 と緑などを選択した場合に、 “選択しない”を外すことは出来ますでしょうか? パターン① 何も選択されていない、もしくは“選択しない”以外を選択している場合で“選択しない”を選んだ場合 ↓ “選択しないをのみ”を選択状態にする パターン② “選択しない”のみが選ばれている状態で、さらに 赤 と緑を選択した場合 ↓ “選択しない”を外して “赤 ”をと“緑”のみを選択する ほんと何度も済みません!!
jun68ykt

2018/08/31 14:55

こんばんは。 > パターン① > パターン② を満たす(と私としては思っている、)コードを、追記4 に記載しました。 ご確認いただいて、 「ちょっと望んでいるのと違う・・・」 という点があればまたお知らせください。
jun68ykt

2018/08/31 23:48

こんにちは。 あらためてご質問を見直しましたが、そもそものご質問のタイトルは 「Underscore.jsにおける絞り込み検索について」 ということでしたね。それを私はどういうわけか、lodashを使った回答をしてしまいました。その点では質問に答えていないともいえます。ベストアンサーを頂戴した後で恐縮ですが、その点は問題ないでしょうか? 参考までに過去には UnderscoreとLodashが統合に向けて議論 https://www.infoq.com/jp/news/2015/06/underscore-lodash-merging といったこともあり、ES6 がすでに定着した現在においては以下のような論調もあります。 Lodash/Underscoreは必要ない(かも) https://qiita.com/ossan-engineer/items/ad5313d84da82c6ac421 (ossan-engineerさん@Qiita による英語記事の翻訳)
hanayona

2018/09/03 05:24

ありがとうございます!ほんと完璧です! まさにやりたかったことです!!lodashは名前だけしか知らなかったのですが、今後色々トライして行きたいと思います、とても勉強になりました!! また、お忙しい中、ご丁寧にご対応頂きありがとうございます! 週末が休日だった為、ご連絡が遅くなってしまったことをお許しください。
hanayona

2018/09/04 06:10

またまた済みません。 上記の挙動につきまして、スマホで設置した場合に、“指定しない”以外は完璧に動作するのですが、 “指定しない”を選択(チェック)した後に検索ボタンを押すと0件選択となってしまいます。 (“指定しない”を選択した後に、検索ボタン以外でもスマホ画面のどこかをクリックすると0件選択となってしまうようです。) 大変お手数ではございますがご確認頂けると助かります。 ほんとお手間をとらせてしまい申し訳ありません!
jun68ykt

2018/09/04 06:54

スマホといっても色々ありますが、その不具合がおきたスマホの機種やOSは何でしょうか?
hanayona

2018/09/04 07:28

済みません、お忙しいところ。 Xperia Z5 SO-01Hで Android 7.0を使用しています。
jun68ykt

2018/09/04 08:01

なるほど〜。私の手元にあるのは iPhone で、今、身近に Adroid端末が無いんですよね。。。
jun68ykt

2018/09/04 08:05

ちなみにお作りになったページを、どこかのサーバーに上げるなどして、私の iPhone から見ることは可能でしょうか?
hanayona

2018/09/04 09:06

早速のご連絡ありがとうございます! 上記でご指南頂いたhttps://jsfiddle.net/jun68ykt/qw64naub/95/をそのまま(手を加えず)cordovaを使って上記の機種でデバックしたのですが、やはり同じ症状で“指定しない”を選択した後に、スマホ画面のどこかをクリックすると0件選択となってしまうようです。 下記のWEBページでもサーバーにアップしてみましたがやはり同じ結果でした。 https://www.3days.biz/page.php?p=un
jun68ykt

2018/09/04 10:33 編集

URLのご連絡どうもです。 手元の iPhone8 を使い、ブラウザは Safari にて、上記URLを開いて、 以下の操作と確認を行い、(一部、望ましい挙動になっていないところはありますが)、検索結果は意図通りになります。 (1) 初期表示では、色、形の Select ともに、「指定しない」が表示され、すべてのデータ6個とも表示される。 (2) 色のセレクタをタップ。画面下部にドラムロールが開き、「指定しない」だけがチェックされている。 (3) ドラムロールの選択肢で、「赤」と「緑」をタップし各々にチェック印が追加される。ただし、この時点では、「指定しない」のチェックは外れない。 ※1:このときに「指定しない」のチェックが外れるようにすることは、無理ではないかと個人的には予想してます。ブラウザ内の select要素と、それを実際にiOS上で表示するUI部品とが、そこまで緊密には結びついてないと思われるので。 (4) ドラムロール右上の「完了」をタップするとドラムロールが消えて、色のSelect に「2項目」と表示される。 (5) 同様にして、形のほうで「丸」を選び、「完了」でドラムロールを閉じたあと「検索」をタップ (6) 意図どおり、罫線の下には「赤い丸」「緑の丸」の2件のみが表示される。 (7) 色のSelectを開いて、「指定しない」をタップ。「指定しない」にチェックがつくが、上記の ※1 と同様に、「赤」と「緑」はチェックされたまま。 ※2: ちなみにここで、ホームボタンを押し、一度ブラウザを隠してから、再度 Safari を開くと、「赤」と「緑」のチェックは外れており、「指定しない」にだけチェックが付いている状態になります。 (8) 同様に「形」のほうでも「指定しない」を選択してドラムロールの「完了」をタップ (9) 上記で両方のSelect には「指定しない」が表示されている。この状態で「検索」をタップ (10) 意図通り、罫線の下には全てのデータ6件が表示される。 確認ですが、hanayonaさんのお手元で発生している不具合としては、先にお知らせいただいたAndroid 端末で上記を行うと、 最後の (10)のところで該当0件になってしまう、ということでしょうか?
hanayona

2018/09/05 02:13

お忙しい中、ご連絡ありがとうございます!! 自分の iPhone7のSafariでも上記のURLを試したのですが、 (1)~(7)までは問題なく動作できるのですが、(8)の「形」のほうでも「指定しない」を選択してドラムロールの「完了」の時に既に選択している(7) 色の「指定しない」が0件選択となってしまいます。 その後、色、形共に「指定しない」を選択後に検索ボタンに限らず、画面のどこかをタップするたびに指定しないが0件選択となってしまう状態が発生いたします(>_<) 。 ちなみにPCでは何の問題もなく作動します。 ほんとお手間をとらせてしまい申し訳ありあません。
hanayona

2018/09/06 05:59

iPhone8で確認したところ問題無く完璧に動作いたしました!! やはり機種により「指定しない」が0件選択となってしまう模様です(>_<) ほんと無理せず、お時間ある時で構いませんのでご確認頂けると幸いです。
guest

0

なんどもすみません、もし可能でしたら“指定しない”を選択した状態で、“赤”“青”などを選択すると指定しないの選択が外れるようにすることは出来ますでしょうか?

投稿2018/08/31 06:41

編集2018/08/31 06:45
hanayona

総合スコア9

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問