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

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

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

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Nuxt.js

Nuxt.jsは、ユニバーサルなSPAが開発可能なVue.jsベースのフレームワーク。UIの描画サポートに特化しており、SSRにおけるサーバーサイドとクライアントサイドのUIレンダリングなどさまざまな機能を持ちます。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

2303閲覧

Vue.js(Nuxt.js)でボタンクリック時にテーブル内のデータの絞り込みを行いたい。

aa316316

総合スコア39

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Nuxt.js

Nuxt.jsは、ユニバーサルなSPAが開発可能なVue.jsベースのフレームワーク。UIの描画サポートに特化しており、SSRにおけるサーバーサイドとクライアントサイドのUIレンダリングなどさまざまな機能を持ちます。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2019/03/11 08:15

前提・実現したいこと

現在Nuxt(Vue.js)でテーブルの絞り込みの実装を行っているのですが、良い実装方法が思いつかないため質問させていただきます。

現状のコードではjsonから以下例のような連想配列をaxiosを使って非同期で取得し、responseをvueファイル内のdataに格納しています。
そして、そのdataをv-forで回し、テーブル内に表示しています。

そこで、テーブルに表示したデータの絞り込みを、検索ボタンクリック時に複数のselectから選択された値で行いたいのですが、
現在解決できていない状況です。

どなたか、よろしければアドバイスいただけますでしょうか。

期待する動作詳細

  • 録画日時、アニメ、ステータスの項目で絞り込みを行いたい。
  • 録画日時のセレクト部分に関してはv-calendarというプラグインのdate-pickerを使用しています。
  • 録画日時に関してはrange(例:2019/03/01 - 2019/03/10)で絞り込みを行いたい。
  • アニメ、ステータスに関してはvalueで絞りこみを行い、value == 0(すべて)の場合はすべての結果を表示したい。

該当のソースコード

vue

1<template> 2 <section> 3 <header class="header"> 4 <!-- 録画日時のセレクト--> 5 <div class="input__item"> 6 <span>録画日時</span> 7 <div class="date-picker__wrapper"> 8 <v-date-picker 9 mode="range" 10   v-model="formOptions.selectedDate" 11 ></v-date-picker> 12 </div> 13 </div> 14 15 <!-- アニメのセレクト --> 16 <div class="input__item"> 17 <label for="anime">アニメ</label> 18 <select id="anime" v-model="formOptions.selectedAnime"> 19 <option value="0">すべて</option> 20 <option value="1">ワンピース</option> 21 <option value="2">ナルト</option> 22 <option value="3">銀魂</option> 23 </select> 24 </div> 25 26 <!-- ステータスのセレクト --> 27 <div class="input__item"> 28 <label for="status">ステータス</label> 29 <select id="status" v-model="formOptions.selectedStatus"> 30 <option value="0">すべて</option> 31 <option value="1">未視聴</option> 32 <option value="2">視聴済</option> 33 <option value="3">保留</option> 34 </select> 35 </div> 36 37 <!-- 検索ボタン --> 38 <div class="btn__wrapper"> 39 <button class="btn btn-search" type="button" @click="doSearch"> 40 <span class="btn__text">検索</span> 41 </button> 42 </div> 43 </header> 44 45  <!-- 以下にテーブルを表示 --> 46 <div class="table__wrapper"> 47 <table class="table"> 48 <thead> 49 <tr> 50 <th>ID</th> 51 <th>録画日時</th> 52 <th>アニメ</th> 53 <th>ステータス</th> 54 </tr> 55 </thead> 56 <tbody> 57 <tr v-for="(data, index) in data" :key="index"> 58 <td>{{data.id}}</td> 59 <td>{{data.date}}</td> 60 <td> 61 <span v-if="data.anime == 1">ワンピース</span> 62 <span v-else-if="data.anime == 2">ナルト</span> 63 <span v-else>銀魂</span> 64 </td> 65 <td> 66 <span v-if="data.status == 1">未視聴</span> 67 <span v-else-if="data.status == 2">視聴済</span> 68 <span v-else>保留</span> 69 </td> 70 </tr> 71 </tbody> 72 </table> 73 </div> 74 75 </section> 76</template> 77 78<script> 79export default { 80 name: 'sample', 81 data() { 82 return { 83 data: [], 84 formOptions: { 85 selectedDate: { 86 start: new Date(), 87 end: new Date() 88 }n, 89 selectedAnime: 0, 90 selectedStatus: 0, 91 } 92 } 93 }, 94 methods: { 95 doSearch() { 96 // ここに検索の絞り込みの関数を記述。 97 } 98 }, 99 mounted() { 100 // jsonファイルからresponseを取得 101 let url 102 switch (this.$router.currentRoute.query.response) { 103 default: 104 url = '/data-sample/sample.json' 105 } 106 107    // 取得したresponseをthis.dataに格納 108 this.$axios.get(url).then(response => { 109 this.data = response.result 110 }) 111 } 112} 113</script> 114 115<style> 116/* スタイルは省略 */ 117</style> 118

以下axiosで取得しているjsonファイルです。

json

1{ 2 "result": [ 3 { 4 "id": "001", 5 "date": "2019/03/11 00:00:00", 6 "anime": 1, 7 "status": 1 8 }, 9 { 10 "id": "002", 11 "date": "2019/03/10 00:00:00", 12 "anime": 2, 13 "status": 2 14 }, 15 { 16 "id": "003", 17 "date": "2019/03/09 00:00:00", 18 "anime": 3, 19 "status": 3 20 }, 21 ] 22} 23

補足情報(FW/ツールのバージョンなど)

"nuxt": "^2.4.0"

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

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

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

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

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

guest

回答2

0

ベストアンサー

dataに直接jsonを読み込んで、それをcomputedでfilterをつかってデータを絞ればいいと思います。
また、if文で検索を絞るのではなくデータにおいては全てjsonで完結させた方がいいですね。

やってることとしては、jsonをdataに読み込んで、filterで各keyに対応するvalueと選択された値が合わないものを全てfalseにし、配列から除外する。
期間に関しては、データ型を合わせるためにmoment.jsを今回は使ってそろえて大小判定をしてstartより小さくendより大きい値にマッチするものを除外しています。

参考例

json

1{ 2 "result": [ 3 { 4 "id": "001", 5 "date": "2019-03-11 00:00:00", 6 "anime": "ワンピース", 7 "status": "未視聴" 8 }, 9 { 10 "id": "002", 11 "date": "2019-03-10 00:00:00", 12 "anime": "ナルト", 13 "status": "視聴済" 14 }, 15 { 16 "id": "003", 17 "date": "2019-03-09 00:00:00", 18 "anime": "銀魂", 19 "status": "保留" 20 } 21 ] 22}

クリックアクションに応じて行うなら

html

1<template> 2 <section> 3 <header class="header"> 4 <!-- 録画日時のセレクト--> 5 <div class="input__item"> 6 <span>録画日時</span> 7 <div class="date-picker__wrapper"> 8 <v-date-picker 9 v-model="formOptions.selectedDate" 10 mode="range" 11 /> 12 </div> 13 <button 14 type="button" 15 @click="isSearch" 16 > 17 検索 18 </button> 19 </div> 20 <!-- アニメのセレクト --> 21 <div class="input__item"> 22 <label for="anime">アニメ</label> 23 <select id="anime" v-model="formOptions.selectedAnime"> 24 <option value=""> 25 すべて 26 </option> 27 <option value="ワンピース"> 28 ワンピース 29 </option> 30 <option value="ナルト"> 31 ナルト 32 </option> 33 <option value="銀魂"> 34 銀魂 35 </option> 36 </select> 37 </div> 38 39 <!-- ステータスのセレクト --> 40 <div class="input__item"> 41 <label for="status">ステータス</label> 42 <select id="status" v-model="formOptions.selectedStatus"> 43 <option value=""> 44 すべて 45 </option> 46 <option value="未視聴"> 47 未視聴 48 </option> 49 <option value="視聴済"> 50 視聴済 51 </option> 52 <option value="保留"> 53 保留 54 </option> 55 </select> 56 </div> 57 </header> 58 <!-- 以下にテーブルを表示 --> 59 <div class="table__wrapper"> 60 <table class="table"> 61 <thead> 62 <tr> 63 <th>ID</th> 64 <th>録画日時</th> 65 <th>アニメ</th> 66 <th>ステータス</th> 67 </tr> 68 </thead> 69 <tbody> 70 <tr 71 v-for="(item, index) in doSearch" 72 :key="index" 73 > 74 <td>{{ item.id }}</td> 75 <td>{{ item.date }}</td> 76 <td>{{ item.anime }}</td> 77 <td>{{ item.status }}</td> 78 </tr> 79 </tbody> 80 </table> 81 </div> 82 </section> 83</template> 84 85<script> 86import sampleJson from '~/static/sample.json' 87import moment from 'moment' 88export default { 89 data() { 90 return { 91 data: sampleJson.result, 92 formOptions: { 93 selectedDate: { 94 start: new Date(), 95 end: new Date() 96 }, 97 selectedAnime: '', 98 selectedStatus: '' 99 }, 100 anime: '', 101 status: '', 102 start: '', 103 end: '' 104 } 105 }, 106 computed: { 107 doSearch() { 108 let list = this.data 109 const anime = this.anime 110 const status = this.status 111 const start = this.start 112 const end = this.end 113 list = list.filter(function (row) { 114 if (anime) { 115 if (row['anime'] !== anime) { 116 return false 117 } 118 } 119 if (status) { 120 if (row['status'] !== status) { 121 return false 122 } 123 } 124 if (start || end) { 125 const time = moment(row['date']).format("YYYY-MM-DD") 126 if (time < start || time > end) { 127 return false 128 } 129 } 130 return row 131 }) 132 return list 133 } 134 }, 135 methods: { 136 isSearch() { 137 this.anime = this.formOptions.selectedAnime 138 this.status = this.formOptions.selectedStatus 139 const selectedDate = this.formOptions.selectedDate 140 this.start = moment(selectedDate.start).format("YYYY-MM-DD") 141 this.end = moment(selectedDate.end).format("YYYY-MM-DD") 142 } 143 } 144} 145</script> 146 147<style> 148/* スタイルは省略 */ 149</style> 150

JSONの値を戻して数字ベースの絞り込み

json

1{ 2 "result": [ 3 { 4 "id": "001", 5 "date": "2019/03/11 00:00:00", 6 "anime": 1, 7 "status": 1 8 }, 9 { 10 "id": "002", 11 "date": "2019/03/10 00:00:00", 12 "anime": 2, 13 "status": 2 14 }, 15 { 16 "id": "003", 17 "date": "2019/03/09 00:00:00", 18 "anime": 3, 19 "status": 3 20 } 21 ] 22}

html

1<template> 2 <section> 3 <header class="header"> 4 <!-- 録画日時のセレクト--> 5 <div class="input__item"> 6 <span>録画日時</span> 7 <div class="date-picker__wrapper"> 8 <v-date-picker 9 v-model="formOptions.selectedDate" 10 mode="range" 11 /> 12 </div> 13 <button 14 type="button" 15 @click="isSearch" 16 > 17 検索 18 </button> 19 </div> 20 <!-- アニメのセレクト --> 21 <div class="input__item"> 22 <label for="anime">アニメ</label> 23 <select id="anime" v-model="formOptions.selectedAnime"> 24 <option value=""> 25 すべて 26 </option> 27 <option value="1">ワンピース</option> 28 <option value="2">ナルト</option> 29 <option value="3">銀魂</option> 30 </select> 31 </div> 32 33 <!-- ステータスのセレクト --> 34 <div class="input__item"> 35 <label for="status">ステータス</label> 36 <select id="status" v-model="formOptions.selectedStatus"> 37 <option value=""> 38 すべて 39 </option> 40 <option value="1">未視聴</option> 41 <option value="2">視聴済</option> 42 <option value="3">保留</option> 43 </select> 44 </div> 45 </header> 46 <!-- 以下にテーブルを表示 --> 47 <div class="table__wrapper"> 48 <table class="table"> 49 <thead> 50 <tr> 51 <th>ID</th> 52 <th>録画日時</th> 53 <th>アニメ</th> 54 <th>ステータス</th> 55 </tr> 56 </thead> 57 <tbody> 58 <tr 59 v-for="(item, index) in doSearch" 60 :key="index" 61 > 62 <td>{{ item.id }}</td> 63 <td>{{ item.date }}</td> 64 <td> 65 <span v-if="item.anime === 1">ワンピース</span> 66 <span v-else-if="item.anime === 2">ナルト</span> 67 <span v-else>銀魂</span> 68 </td> 69 <td> 70 <span v-if="item.status == 1">未視聴</span> 71 <span v-else-if="item.status == 2">視聴済</span> 72 <span v-else>保留</span> 73 </td> 74 </tr> 75 </tbody> 76 </table> 77 </div> 78 </section> 79</template> 80 81<script> 82import sampleJson from '~/static/sample.json' 83import moment from 'moment' 84export default { 85 data() { 86 return { 87 data: sampleJson.result, 88 formOptions: { 89 selectedDate: { 90 start: new Date(), 91 end: new Date() 92 }, 93 selectedAnime: '', 94 selectedStatus: '' 95 }, 96 anime: '', 97 status: '', 98 start: '', 99 end: '' 100 } 101 }, 102 computed: { 103 doSearch() { 104 let list = this.data 105 const anime = this.anime 106 const status = this.status 107 const start = this.start 108 const end = this.end 109 list = list.filter(function (row) { 110 if (anime) { 111 if (row['anime'] !== Number(anime)) { 112 return false 113 } 114 } 115 if (status) { 116 if (row['status'] !== Number(status)) { 117 return false 118 } 119 } 120 if (start || end) { 121 const time = moment(row['date']).format("YYYY-MM-DD") 122 if (time < start || time > end) { 123 return false 124 } 125 } 126 return row 127 }) 128 return list 129 } 130 }, 131 methods: { 132 isSearch() { 133 this.anime = this.formOptions.selectedAnime 134 this.status = this.formOptions.selectedStatus 135 const selectedDate = this.formOptions.selectedDate 136 this.start = moment(selectedDate.start).format("YYYY-MM-DD") 137 this.end = moment(selectedDate.end).format("YYYY-MM-DD") 138 } 139 } 140} 141</script> 142 143<style> 144/* スタイルは省略 */ 145</style> 146

投稿2019/03/11 09:57

編集2019/03/12 09:24
sauzar18

総合スコア163

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

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

aa316316

2019/03/11 14:08

ご回答ありがとうございます!大変参考になります! ちょっとまだ実際にコードを書いて確認ができていないのですが、 上記のようにcomputedを使った記述になると、セレクトで値を選択した時に絞り込まれてしまうのでしょうか?できればボタンをクリック時に各セレクトで選択した値の絞り込みを行いたいと考えているのですが、そのような場合はmethods以下で上記のcomputed内のコードと同じような書き方をすれば、同様に絞り込みを行うことができるのでしょうか? まだ自分で確認できていないうちの確認で申し訳ありません。あとで自分でもいじって確認させていただきます! よろしければアドバイスいただけるとうれしいです。
sauzar18

2019/03/12 01:08

v-modelに紐づいている以上、即時にデータがバインディングされてしまうので、値を選択した段階で絞り込まれてしまいます。 methodsで引数を用いて行ってもおそらく一緒かとは思うのですが、考え的にはボタンを押した際にバインディングがされるようにすればって感じですかね。
sauzar18

2019/03/12 01:22

methodsのファンクションを起動した際に別のdataに値を移し替えればいけましたね。
aa316316

2019/03/12 02:52

ご丁寧なアドバイスに加え、具体例まで出していただきとても助かります。ありがとうございます。 上記、クリックアクションに応じて行う場合のコードを参考に試してみたのですが、 結果まだ期待する動作を実現することができませんでした。 原因としてはcomputed内のfilter部分で 'row is not defined'というエラーが出ており、console.log(row)で中身を確認したところ、json内の配列([{id:.., date:..}, {id:.., date:..}])がそのまま入っておりました(自分の理解ではrowにはlistに入れた配列以下の各オブジェクトが入っていると考えていました) for文などを利用して配列内の各オブジェクトを指定したらworkを取り出せるかなと思い、for(略){ cosole.log(row[i]['work])}としてみましたが、取り出せませんでした、、 また、html部分のselectのoptionのvalueに関してですが、後ほどAPIへのリクエストで送る数値として決まってしまっており、Integerからstringへ変更することができません。(本番ではjsonではなくAPIを使用する予定です) ただこれは、おそらくcomputed内の条件分岐を工夫すればなんとかなりそうだと思っているので、もう少し考えてみます、、 おそらく自分が上記コードを理解しきれていないだけだと思いますが、お時間取らせてしまいすみません、、
sauzar18

2019/03/12 03:17 編集

どういうデータを扱ってるのかがわからないとなんとも言えないのとAPIがどんなresponseを返すのかによっても処理が変わってくるんですが、filterは配列に対して使用するものなのでデータがもしかしたら二次配列になっているとかだとエラーでますね。 例えば二次配列の場合は配列が一つしか入ってない場合はthis.data[0]とかで取得するとか、flat系の処理をして二次配列から一次配列に統合してあげるとかですかね
sauzar18

2019/03/12 13:22

追記したんですが、これでもダメですか?
aa316316

2019/03/13 15:05

ありがとうございます! 返事遅れましてすみません、無事上記で期待通り動かすことができそうです! なんども質問してしまいましたが、大変助かりました、 ありがとうございました!
guest

0

dataを直接バインドせずに、computedでフィルター処理をしたものをバインドすればリアクティブに絞り込み可能です。

絞り込みに使う変数が更新される毎にレンダリングするデータも変更されます。

追記

data: []
filterData: []
検索ボタンが押された時にmethodsのhandleClick内で検索条件を元にフィルタリングしてfilterDataを更新する形はどうでしょうか?
要素の更新の際は注意してくださいね。

投稿2019/03/11 09:37

編集2019/03/13 01:32
_Victorique__

総合スコア1392

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

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

aa316316

2019/03/12 02:54

ご回答ありがとうございます! 上記でもコメントさせていただいていますが、現在検索ボタンをクリック時に絞り込みを行いたく、その方法の実現を模索しています。。 よろしければアドバイスいただけますと、大変助かります。
_Victorique__

2019/03/12 08:50 編集

何故クリック時に絞り込みたいのでしょうか? 個人的な疑問なので教えていただけないでしょうか?
aa316316

2019/03/12 09:04

即時で絞り込みが反映されるよりも、ボタンクリック時に実行されるほうがユーザー体験的な意味で良いと感じるからでしょうか。感じ方はひとそれぞれだと思いますが、、
_Victorique__

2019/03/12 09:41

UI/UXを考えると一回ボタンを押す動作が多くなることはユーザーに煩わしさを与えることになります。実際に触れてみると良くわかると思います。
aa316316

2019/03/12 10:08

確かに、ユーザーの動作が一回多くなってしまいますが、自分はセレクトで条件選択時に表示結果が変わってしまう点に違和感を感じてしまいました。また、検索ボタンがない検索窓に慣れていないユーザーの方が多い(一般的)と感じたため、今回はボタンありで実装しようとしています!
_Victorique__

2019/03/12 10:39

これでもちょっと回りくどいですね。 サーバーサイドから逐一取得するのじゃダメですか?
aa316316

2019/03/13 15:06

ありがとうございます! 追記参考にさせていただきました! 色々な回答参考にし、無事期待通りの動作が実現できそうです! 大変おせわになりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問