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

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

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

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

Q&A

1回答

1097閲覧

vue で toggle を変更するのに不要そうなプロパティがあるるのですが外すとうまく動きません。

sususu

総合スコア99

Vue.js

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

0グッド

0クリップ

投稿2021/09/26 01:12

編集2021/09/26 09:44

トグルスイッチを配列から作成しています。
不要だと思われるプロパティがあるのですがそれを削除するとなぜか動きません。
それがなぜ必要なのか、また不要そうなプロパティを削除しもっときれいに書く方法があればご教授頂きたいです。

下記「?」がついているコードが不要かと思われるコードで 3 箇所あります。

html

1<div class="child-content" v-for="(tag, i) in tags" :key="tag.id"> 2 <div class="child-wrapper"> 3 <div class="string">{{ tag.name }}</div> 4 <div v-bind:class="{on: tagToggle}"></div> <!-- ? --> 5 <div class="toggle" v-bind:class="{on: tag.is_active}" v-on:click="changeTagToggle(i)"></div> 6 </div> 7</div>

javascript

1... 2data() { 3 return { 4 ... 5 tags: [], 6 tagToggle: true, //? 7 ... 8 } 9}, 10... 11 12... 13changeTagToggle: function(i) { 14 this.tagToggle = !this.tagToggle //? 15 this.tags[i]["is_active"] = !this.tags[i]["is_active"] 16 this.resetPoint() 17}, 18... 19 20... 21.toggle{ 22 display: table-cell; 23 background-image: url(./../assets/toggle.png); 24 background-color: #020e7a; 25 width: 50px; 26 height: 24px; 27 background-position: 0px 0px; 28} 29.toggle.on{ 30 background-position: 0px -24px; 31} 32... 33

tags [] の中身は下記のような配列です。

json

1[ 2 { 3 id: 1, 4 is_active: true, 5 name: "hoge" 6 }, 7 { 8 id: 2, 9 is_active: true, 10 name: "fuga" 11 } 12 ... 13]

配列内の「is_active」の属性値を変えてスイッチの見た目を切り替えています。

なぜ「tagToggl」プロパティを切り替える必要があるのかどなたかご教授頂ければ幸いです。
以上よろしくお願いいたします。

【コードを追加】
既定の文字数を超えているのでCSSは必要な個所以外は省略しています。

<template> <div class="accordion-container"> <div class="parent-accordion-header" v-bind:class="{on: isOpenSearchMenu}"> <div class="parent-header-content" v-on:click="searchMenu">検索メニュー</div> <div class="parent-header-close"> <div class="close"> <div v-on:click="searchMenu">x</div> </div> </div> </div> <div class="parent-accordion" v-bind:class="{on: isOpenSearchMenu}"> <div class="child-accordion-container"> <div class="child-accordion-header" v-on:click="isOpenSearchAccordion =! isOpenSearchAccordion"> <div class="child-header-content">地名検索</div> </div> <div class="child-accordion" v-if="isOpenSearchAccordion"> <div class="child-content"> <div class="search-container"> <button class="search-place-button" v-on:click="searchPlace"><img class="icon" src="@/assets/search.png"></button> <input type="text" id="search-text" class="search-place" placeholder="地名か住所から検索" v-model="searchText" v-on:keyup.enter.exact="searchPlace"> <button class="remove-search-place" v-if="searchText" v-on:click="removeSearchText()">x</button> </div> </div> </div> </div> <div class="child-accordion-container"> <div class="child-accordion-header" v-on:click="isOpenTagAccordion =! isOpenTagAccordion"> <div class="child-header-content">タグ検索</div> </div> <div class="child-accordion" v-if="isOpenTagAccordion"> <div class="child-content" v-for="(tag, i) in tags" :key="tag.id"> <div class="child-wrapper"> <div class="string">{{ tag.name }}</div> <div class="toggle" v-bind:class="{on: tag.is_active}" v-on:click="changeTagToggle(i)"></div> </div> </div> </div> </div> </div> </div> </template> <script> export default { name: 'searchMenu', components: { }, data() { return { tags: [], isOpenSearchMenu: false, isOpenSearchAccordion: true, isOpenTagAccordion: true, filterParams: {}, error: null, searchText: null, } }, mounted (){ this.fetchTags() }, methods: { searchMenu: function() { this.isOpenSearchMenu = !this.isOpenSearchMenu; }, closeSearchMenu: function(){ this.isOpenSearchMenu = false; }, searchPlace: function(){ this.$emit("search-place") }, fetchTags: async function (){ await this.axios.get( '/map/api/tags/' ).then( (response) => { this.tags = response.data.tags; for(let i = 0; i < this.tags.length; i++){ this.tags[i]["is_active"] = false; } console.log(this.tags) } ).catch( (error) => { this.$toasted.error("データの取得に失敗しました。"); console.log(error) } ) }, removeSearchText: function(){ this.searchText = null; }, changeTagToggle: function(i) { this.$set(this.tags[i], "is_active", !this.tags[i]["is_active"]); this.resetPoint() }, resetPoint(){ /** * ?[タグ名]=true の形式でフィルタとなるパラメータを作成しポイントを作成し直す。 */ this.filterParams = {}; for (let i = 0; i < this.tags.length; i++) { if (this.tags[i]["is_active"]) { let parameter = this.tags[i].name this.filterParams[parameter] = true; } } this.$emit('reset-points', this.filterParams) } } } </script> <style scoped> .child-wrapper{ display: table; justify-content: center; } .string{ display: table-cell; width: 200px; color: dimgray; } .toggle{ display: table-cell; background-image: url(./../assets/toggle.png); background-color: #020e7a; width: 50px; height: 24px; background-position: 0px 0px; } .toggle.on{ background-position: 0px -24px; } </style>

上記のコードだと下記の挙動を取ります。
・chrome の拡張機能で vue を確認するとすべての値に変化がありません。
・しかしAPI自体は想定するレスポンスを返しているので tags[] の中身は正常に更新されているようです。
イメージ説明

下記のようなコードを追加して、toggle を変更したときに必ず変わる値を HTML にバインドすると、正常に動作します。今回の場合はアクティブのタグトグルをカウントしてみます。
【追加コード】
HTMLに値をバインドする。

javascript

1... 2<div class="child-header-content">タグ検索({{ isActiveTagToggleCount }}</div> 3...

isActiveTagToggleCount プロパティを追加。

... data() { return { tags: [], isOpenSearchMenu: false, isOpenSearchAccordion: true, isOpenTagAccordion: true, filterParams: {}, error: null, searchText: null, isActiveTagToggleCount: 0, } }, ...

トグルを変更したらカウントの増減を行う。

... changeTagToggle: function(i) { this.tags[i]["is_active"] = !this.tags[i]["is_active"] if(this.tags[i]["is_active"]) { this.isActiveTagToggleCount += 1; }else{ this.isActiveTagToggleCount -= 1; } this.resetPoint() }, ...

上記の通りに修正すると下記の通りに chrome の拡張機能上でも値が書き換わるのが確認できます。
イメージ説明

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

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

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

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

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

guest

回答1

0

私の環境では該当部分を削除しても動いてしまいましたが、変更検出の注意事項が影響しているのだと思います。
配列の子要素に直接代入をしてもVueは変更をリアクティブに出来ません。

なので以下の変更は本来Vueが検知出来ないものになります。

js

1this.tags[i]["is_active"] = !this.tags[i]["is_active"]; // --- 1

そのためthis.tagsの値自体は変わっていても以下のDOMは更新されません。

html

1<div class="toggle" v-bind:class="{on: tag.is_active}" v-on:click="changeTagToggle(i)"></div> 2

しかし、以下の変更はVueが検知できます。

js

1this.tagToggle = !this.tagToggle; // --- 2

この変更によって以下のDOMが更新されます。

html

1<div v-bind:class="{ on: tagToggle }"></div>

Vueの内部仕様はわかりませんが2の更新によって1の更新が誘発されているのかもしれません。

結論

js

1this.$set(this.tags[i], "is_active", !this.tags[i]["is_active"]);

上記コードでおそらく該当部分を削除しても動くと思います。

追記

わかりません。
CodeSandBoxで環境を再現しました。
何か差異はありますか?

投稿2021/09/26 03:33

編集2021/09/26 06:52
k4a

総合スコア983

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

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

sususu

2021/09/26 06:01

ご回答ありがとうございます。 リアクティブについて知らなかったのでとても助かりました。 ありがとうございます。 しかし、上記のように変更したのですが、まだうまく動いていない状況です。 is_active はうまく変更されているようなのですが、class="toggle" に "on" 属性が追加されず toggle の見た目がオフの状態のままです。 何かほかにご教授頂ければ幸いです。 どうぞよろしくお願いいたします。
sususu

2021/09/26 09:21 編集

わざわざコードまで用意いただいてありがとうございます。 正直差異はないかと思います。なにか見落としている可能性がありそうです。。。 一応すべてのコードを記載いたしました。 よろしくお願いいたします。
k4a

2021/09/27 02:14

追加のコードでも動作を確認しましたが、私の環境ではどうやっても正常に動いてしまいました。 お力になれず申し訳ないです。
sususu

2021/09/27 04:16

この度はご協力いただきありがとうございました。 $set などは全く知らなかったのでとても勉強になりました。 何か環境が影響しているかもしれませんが、今回はとりあえず、適当に値をHTMLに渡してトグルを更新したいと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問