質問: ''; // 受け取った配列をループで処理 // 出力するHTMLの整形 jQuery.each(results, function() { html += ''; html += this.name; html += ''; }); // HTMLに出力 $('#items').empty().append(html); } // ページ読み込み時はすべてのアイテムを出力する $(window).on('load', function(){ outputResults(items); });
回答: こんにちは。 まず前提として、`lodash` の `where` は以下 に記載されているように、 v4 から削除されており、替わりに filter を使うことになっていますので、以下の回答もこれに従っています。 ご質問では > > マルチのセレクトボックスで複数選択し検索したい > > > とのことですが、その場合は filter の第2引数に、条件にマッチするかどうかにより `true` または `false` を返す関数を与えれば実現できます。 具体的な修正案の一例を以下に挙げます。単一選択の場合はご質問にあるコードと同様に、 ``` // データの中から一致するオブジェクトを検索 var results = _.filter(items, query); ``` とするところを、以下のように修正すればよいかと思います。 ``` // データの中から一致するオブジェクトを検索 var results = _.filter(items, function(item) { return ( (query.colors.includes("") || query.colors.includes(item.color)) && (query.types.includes("") || query.types.includes(item.type)) ); }); ``` * `select`が複数選択可能な場合、`.val()` は選択された ``の value を要素とする配列になります。 * したがって、``の id と、 `query` のプロパティ名である`color`と`type`は、`color`**s** および、`type`**s** と複数形にしたほうがよいです。 * `query.colors` と `query.types` に対して、includes を使って、全item の中で条件を満たすものについて `true` を返すような関数を、`filter` の第2引数に渡します。 以下に上記のサンプルを作成しました。(使用している lodash のバージョンは、4.17.10です) * 単一選択: * 複数選択: 以上参考になれば幸いです。 **追記** さはさりながら、`_.filter` の第2引数に関数を渡すのであれば、そもそも JavaScriptの標準のArray.prototype.filter() を使って以下のように書けます。この場合は lodashは不要になります。 ``` // データの中から一致するオブジェクトを検索 var results = items.filter(function(item) { return ( (query.colors.includes("") || query.colors.includes(item.color)) && (query.types.includes("") || query.types.includes(item.type)) ); }); ``` **追記2** 複数選択可能な場合、color**s**およびtype**s**と、複数形にしたほうがよい点を回答に加筆しました。 **追記3** コメントのほうで頂いた、 > > “指定しない”と他の選択肢を連動させることは可能でしょうか? > > > との件ですが、`` の中にある、どの``が選ばれているかが変化したときの `chage`イベントハンドラに、ご要望の処理を設定することで可能です。 具体的には例えば以下を追加します。 ``` // ”指定しない" が選択されたら、他の選択肢は選ばれていない状態にする $('select').on('change', function() { if ($(this).val().includes("")) $(this).val([""]); }); ``` 上記を追加すると、以下のような効果があります。 例えば、`赤` と`緑`が選ばれている状態で、さらに `選択しない`を選択状態にすることを想定します。すると上記で設定した`change`ハンドラ `function() { ... }` が呼ばれて、関数の中で`$(this).val()`とすると、選択された `option` の valueの配列が取れるので、今想定している状況では、`["", "red", "grren"]` と、3つの要素を持ちますが、これらの要素のうち、空文字列 `""` が含まれているということは(= `.includes("")` が true ならば)、「指定しない」が選ばれたことを示しています。その場合は、「指定しない」だけが選ばれていることを表す配列 `[""]` を、`$(this).val(設定値)` に与えると、「指定しない」ではない他の選択肢は選ばれていない状態にすることができます。 ※以下にサンプルを作成しました。 **追記4** コメントのほうから、 > > 何度もすみません、もし可能でしたら > > ・・・ > > > ということで頂戴した、追加要件を実現する方法です。 ご希望の挙動を満たすには、`change`イベントが発生したときに選択状態にした``の value配列を保存しておいて、次に新たな`change`イベントが発生したときに選択されている``の value配列と、保存しておいた前回の`change`イベント発生時に選択状態にした値の配列とを比較して、次の望ましい状態を作ってから、再度、保存しておく処理が必要になると思います。どこに保存しておくかですが、 `data-`属性に保存するというのが一案です。 上記の比較によって判断するべき条件は、 * 前回の`change`イベント発生時に、最終的に選択状態にした値の配列が、`[""]`であるか否か です。以下は上記の実装例です。前回の選択値が`""]`であるかどうかの判定のために、 lodash の [isEqual を使用しています。 ``` // optionの選択状態が変更されたときの設定 $('select') .data('prev-values', [""]) .on('change', function() { if ($(this).val().includes("")) { if (_.isEqual($(this).data('prev-values'), [""])) { $(this).val($(this).val().filter(v => v!="")); } else { $(this).val([""]); } } $(this).data('prev-values', [...$(this).val()]); }); ``` 上記のサンプルを に作成しました。 **追記5** 「onChangeハンドラの中で、対象のchangeイベントが発生する前の value を取得するにはどうしたらいいか?」というお題は、以下にも投稿されています。 stackoverflow: Getting value of select (dropdown) before change 上記の回答の中にも、`change`イベントが発生して選択された値を保存しておく場所として、 `data-`属性を使うというものが、いくつか見つかります。 **追記6** 追記4 に書いたコードの以下の部分 ``` $(this).val($(this).val().filter(v => v!="")); ``` は、以下のように書くことで少し短くすることができます。 ``` $(this).val($(this).val().filter(v => v)); ```