#やりたいこと
下の画像のように、プルダウン選択が二つある場合、
一つ目で選んだ項目を二つ目の選択肢から消したい。
#例えば・・
industriesというオブジェクトがあって、表示は日本語,選択時のvalueはkeyのidとなる
industries = {1: スポーツ, 2: メディア, 3: 建設}
1つ目のプルダウンで 1:スポーツ を検索すると
2つ目のプルダウンでは {2: メディア, 3: 建設} のみ選択肢に現れるようにしたい。
#やってみたこと
filterメソッドを駆使してみたものの、配列じゃないと使えない。
1つ目に選択したidを引数に、下記のメソッド発火
this.industriesには {1: スポーツ, 2: メディア, 3: 建設} が入っているとしてください。
js
1 fetch_sub_industries(industry_id) { 2 if(industry_id) { 3 this.sub_industries = Object.keys(this.industries).filter(function (sub_industry_id) { 4 return sub_industry_id !== industry_id 5 }) 6 console.log(this.sub_industries) 7 } 8 },
結果は [2, 3] となるが、ここから {2: メディア, 3: 建設} というような検索も難しい。。
どなたかご教示いただけると助かります。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
こんにちは
ご質問に挙げられているコードの意図に沿って、関数 fetch_sub_industries
は、 this.industries
を新しいオブジェクトで書き換えるものとします。この前提で、filter
を使うのであれば、以下のようにすればよいかと思います。
javascript
1function fetch_sub_industries(industry_id) { 2 let entries = Object.entries(this.industries); 3 entries = entries.filter(([id]) => +id !== industry_id); 4 this.industries = Object.fromEntries(entries); 5}
- **動作確認用 CodePen: **https://codepen.io/jun68ykt/pen/JjowGyG?editors=0012
追記
配列やオブジェクトの操作で便利なライブラリ lodash の _.omit を使うと、以下のように手短かに書けます。
javascript
1function fetch_sub_industries(industry_id) { 2 this.industries = _.omit(this.industries, industry_id); 3}
- **動作確認用 CodePen: **https://codepen.io/jun68ykt/pen/wvBRMqj?editors=0012
追記2
新しいオブジェクトを作って、this.industries
に再度代入するのではなく、現状の this.industries
から、単に industry_id
で指定されるプロパティを除去すればよいのであれば、以下でもよいかと思います。
javascript
1function fetch_sub_industries(industry_id) { 2 delete this.industries[industry_id]; 3}
- **動作確認用 CodePen: **https://codepen.io/jun68ykt/pen/abzPdgm?editors=0012
追記3
上記の回答は、ご質問にある関数 fetch_sub_industries
を、ご質問にある意図通りにするための修正案ですが、2つの<select>
を連動させて、1つ目の seelct
で選ばれた選択肢を、2つ目の select
では表示させないようにすることが主目的なのであれば、2つのselect
は両方とも常にoption
を3つ持つようにしておき、1つ目で選ばれた選択肢を2つ目で非表示にするために、CSSの display
を none
にするという手もあるかと思います。
以下、そのサンプルです。
- **動作確認用 CodePen: **https://codepen.io/jun68ykt/pen/QWwzNGL?editors=1010
追記4
コメントから頂きました
ソースをみて不明な点があり、
について回答します。
まず、
MDNの JavaScript のデータ型とデータ構造 の中にある、Object のセクションのプロパティの説明に、以下のように書かれています。
キー値は String 値または Symbol 値です。
これを確かめるために、
javascript
1this.industries = { 1: "スポーツ", 2: "メディア", 3: "建設" }; 2 3console.log(Object.keys(this.industries));
とすると、以下で確認できるように、 [ 1, 2, 3 ]
ではなく、 ["1", "2", "3"]
と表示されます。
- **動作確認用 CodePen: ** https://codepen.io/jun68ykt/pen/qBELPgY?editors=0012
すなわち、this.industries
のプロパティのキーは、 1,2,3 という整数値ではなく、文字列の "1" , "2", "3" として保持されています。
同様に、一番初めに挙げた回答コード
- **動作確認用 CodePen: ** https://codepen.io/jun68ykt/pen/JjowGyG?editors=0012
にある、以下の行
javascript
1let entries = Object.entries(this.industries);
で得られる entries
を console.log で表示すると、以下のようになり、エントリーのキーは、"1", "2", "3" と、文字列として取得されてくることが確認できると思います。
[["1", "スポーツ"], ["2", "メディア"], ["3", "建設"]]
上記の配列 entries
を filter でループさせるときに、filter の引数として与える関数には、上記の
["1", "スポーツ"]
という形、すなわち長さが2で先頭要素が元のオブジェクトのプロパティのキー(文字列です)、二番目の要素がプロパティの値である配列が引数として渡されてくるので、以下のようにすれば、key
, value
という変数名で、この配列の要素を受け取れます。(以下のコードで [key, value]
という書き方は分割代入と呼ばれ、追記5 に説明しました。)
javascript
1entries.filter(([key, value]) => { 2 // 何らかの判定ロジック 3 retrurn trueまたはfalse 4})
function fetch_sub_industries(industry_id)
では、プロパティのキーが、industry_id
と等しいかだけを見ればよいので、value
は不要で、key
のほうは id と呼ばれる値なので
javascript
1entries.filter(([id]) => { 2 // 何らかの判定ロジック 3 retrurn trueまたはfalse 4})
と書いて、id
という変数名で ["1", "スポーツ"]
の "1"
を受け取ります。
次に、// 何らかの判定ロジック
の部分を書いて、その結果を反映して true かfalse を返すようにします。
id
が function fetch_sub_industries
に渡される industry_id
に等しくない場合にのみ、filter によって残されればよいので、
javascript
1entries.filter(([id]) => { 2 return id !== industry_id 3})
と書けばよさそうですが、これだと、うまくいきません。
なぜなら、関数fetch_sub_industries
の引数 industry_id
のほうは文字列ではなく、たとえば 1
だったりの整数が渡され、他方、
javascript
1entries.filter(([id]) => { 2 return id !== industry_id 3})
と書いた場合の filter のループで呼ばれる関数の引数(の配列要素の) id
には "1"
だったりの文字列が渡されてくるため、
id !== industry_id
は(両辺の型が違うので、値を比較するまでもなく、)必ずtrueになります。したがって fetch_sub_industries(1)
としたときも ["1", "スポーツ"]
が除外されず、結果としてthis.industries
は元のオブジェクトの3つのエントリ(キーと値の組)をどれも持つものとなってしまいます。以下で確認できます。
- **動作確認用 CodePen: ** https://codepen.io/jun68ykt/pen/rNaoYjJ?editors=0012
!==
によって意図した判定が行われるには、両辺の型を揃える必要がありますが、回答のコードでは、関数fetch_sub_industries
の引数industry_id
は整数値が渡されることを前提として、両辺を数値にあわせることにしました。そのためには filter のループで使われる id
のほうを文字列から数値に変換しなければなりません。数字の文字列である id
を数値に変換する方法としては、Number(id)
や parseInt(id)
(より厳密には、parseInt(id, 10)
) とすればよいですが、もっと簡単に書く方法として
+id
と書くことでも数値が得られます。 これにより、id
がたとえば "1"
ならば、数値の 1
が得られます。このような +
は単項加算(unary plus)と呼ばれます。以下は MDN の単項加算の説明です。
- MDN: 単項加算 (+)
単項加算を使って、!==
の両辺を数値にあわせて、
javascript
1entries.filter(([id]) => { 2 return +id !== industry_id 3})
とすれば、意図通りに filter が機能します。さらに、アロー関数の本体が1行であり return で値を返しているので、上記を詰めて、
javascript
1entries.filter(([id]) => +id !== industry_id)
と書いたものが、回答に挙げたコードになります。
ちなみに、もし、id
の型に合わせて、文字列の比較にするならば、industry_id
のほうを文字列にする必要があるので、たとえば
javascript
1entries.filter(([id]) => id !== `${industry_id}`)
のようにします。
- **動作確認用 CodePen: ** https://codepen.io/jun68ykt/pen/vYEvWpB?editors=0012
上記のように、厳密な比較の !==
を使うと、数値か文字列のいずれかに型を合わせる必要がありますが、これがやや煩雑と思えば、厳密でない比較の !=
を使って
javascript
1id != industry_id
と書くことで、文字列である id
のほうが、数値(Number型)に変換されてから、その値が、industry_id
と等しくないかを判定します。!==
と !=
の違い(あるいは ===
と ==
の違い)を確認するには、以下に説明があります。
- MDN: 等価演算子の使用
上記のような場合、 id
と industry_id
とで、いずれかの型を他方に、(たとえば上記のように id
に単項加算を追加して、)明示的に合わせて ===
や !==
で比較したほうがよいのか、あるいは ==
や !=
を使って、型を明示的に合わせることを不要にして比較するほうがよいのかについては、「時と場合による」という考え方もできますが、ひとつのガイドとして、javascript のコードチェックツールの ESLint の様々なルールの中に
==
および!=
は使わないようにして、===
および!==
を使うべき
という、以下のルール
- ESLint: Require === and !== (eqeqeq)
It is considered good practice to use the type-safe equality operators === and !== instead of their regular counterparts == and !=.
があります。ですので、(私もそうですが)ふだん ESLint を効かせながらコードを書いていると、 !=
を使った
id != industry_id
というコードを書くとESLintに警告されるので、型を合わせて ===
および !==
を使うほうに慣れてきます。(実際私は、ここ数年、業務では ==
および !=
をほとんど使ってないです。)
追記5
もう一点、
this.industriesが
[[1: "スポーツ"], [2: "メディア"], [3: "建設"]]
のようになっていて、
.filter(([id]) =>
で1,2,3が回るようになる?とすれば、なぜこれで1,2,3が回るのか。
についてですが、2つの要素を持つ配列 ["1", "スポーツ"]
を引数にとる関数を書くときに、この配列を ary
という引数で受けて、
javascript
1const f = (ary) => { 2 const id = ary[0]; // "1" 3 const name = ary[1]; // "スポーツ" 4 ・・・ 5} 6 7f(["1", "スポーツ"]); 8
と書くこともできますが、引数の ary
を [id, name]
として
javascript
1const f = ([id, name]) => { 2 console.log(id); //=> "1" 3 console.log(name); //=> "スポーツ" 4 ・・・ 5} 6 7f(["1", "スポーツ"]);
と書くことで、id
と name
に直接、配列の先頭と2番目の要素が得られます。これは、配列の分割代入を、関数の引数に使った書き方です。分割代入については以下に説明されています。
- MDN: 分割代入
また、MDNのObject.entriesの説明 の冒頭にも、以下のようなサンプルがあります。
javascript
1const object1 = { 2 a: 'somestring', 3 b: 42 4}; 5 6for (let [key, value] of Object.entries(object1)) { 7 console.log(`${key}: ${value}`); 8}
上記では、、Object.entries
で得られる配列の要素を for ・・・ of
のループで得るときに、・・・
の部分を[key, value]
と書くことで分割代入を使い、キーと値を得ています。
以上、参考になれば幸いです。
投稿2020/01/21 12:34
編集2020/01/22 01:46総合スコア9058
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/01/21 16:19
2020/01/21 16:45
2020/01/21 23:05
2020/01/21 23:34
2020/01/22 01:01
2020/01/22 01:09