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

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

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

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

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Vue CLI

Vue CLIは、Vue.jsでアプリケーション開発を行うためのコマンドラインインタフェース(CLI)に基づいた開発ツールです。インタラクティブなプロジェクトの雛形や設定なしで使用できるプロトタイプの作成など、さまざまな機能が用意されています。

Q&A

解決済

1回答

1281閲覧

【Vue × Realtime Detabase】メッセージを右ボタンで削除をしたいです

TMTN

総合スコア53

Vue.js

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

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Vue CLI

Vue CLIは、Vue.jsでアプリケーション開発を行うためのコマンドラインインタフェース(CLI)に基づいた開発ツールです。インタラクティブなプロジェクトの雛形や設定なしで使用できるプロトタイプの作成など、さまざまな機能が用意されています。

0グッド

0クリップ

投稿2021/05/13 03:01

編集2021/05/14 14:43

#メッセージを右ボタンで削除をしたいです。

Vueとfirebaseを使用してポートフォリオを現在作成しております。

そこで現在チャットを実装しており、メッセージを投稿者のみ削除できるようにしたいです。
下記にて現在のコードを掲載しております。

https://qiita.com/akicho8/items/8522929fa619394ac9f4

こちらの記事を参考にさせていただき、メッセージを右クリックしたらdeleteMessage()が発火するようにしてます。

画像

しかし、js部のdeleteMessage() {firebase.database().ref().remove()にある、ref()部にてどのように記述したら
青で囲ったidが取得できるのか分からず困っております。。

合わせて投稿者のみ削除できるようにするにはどのようにしたらいいのかも教えて頂けると幸いです。
お力添えを宜しくお願い致します。

html

1<div @click.right.prevent="deleteMessage" class="mymessage"> 2 <nl2br tag="div" :text="message" /> 3</div>

js

1deleteMessage() { 2 firebase 3 .database() 4 .ref() 5 .remove(); 6 this.$swal({ 7 title: "内容確認", 8 text: "mメッセージを削除しますか?", 9 icon: "warning", 10 buttons: true, 11 dangerMode: true 12 }).then(willDelete => { 13 if (willDelete) { 14 this.$swal("メッセージを削除しました", { 15 icon: "success" 16 }); 17 this.$router.go({ 18 path: `/board/${this.$route.params.uid}`, 19 force: true 20 }); 21 } else { 22 this.$swal("キャンセルしました。"); 23 } 24 }); 25 } 26 }

css

1.mymessage { 2 display: inline-block; 3 position: relative; 4 margin: 0 20px 0 0; 5 padding: 10px; 6 max-width: 460px; 7 border-radius: 12px; 8 background: #00ec0ccb; 9 z-index: 5; 10 user-select: none; 11 }

#追記

methods: { // スクロール位置を一番下に移動 scrollBottom() { this.$nextTick(() => { //this.$nextTickは、再描画を待つ。 //絶対値からbody要素の高さを取得 window.scrollTo(0, document.body.clientHeight); }); }, childAdded(snap) { //snapshotとは、ある時点における特定のデータベース参照にあるデータの全体像を写し取ったもの //childAdded:データベースからアイテムのリストを取得する関数 // 受け取ったメッセージをchatに追加 const message = snap.val(); //イベントのときにデータベース内の「message」データを取得。 // データベースに新しい要素が追加されると随時呼び出される this.chat.push({ key: snap.key, name: message.name, image: message.image, message: message.message, userid: message.userid, time: message.time, }); this.scrollBottom(); //スクロールの一番下に追加。 }, doSend() { const time = time; if (this.user.uid && this.input.length) { // firebaseに書き込まれたメッセージを追加 firebase .database() .ref(this.$route.params.id) .push( { message: this.input, name: this.user.displayName, image: this.user.photoURL, userid: this.user.uid, time: firebase.database.ServerValue.TIMESTAMP, }, () => { this.input = ""; // フォームを空にする } ); console.log(time); } }, deleteMessage() { firebase .database() .ref() .remove(); this.$swal({ title: "内容確認", text: "メッセージを削除しますか?", icon: "warning", buttons: true, dangerMode: true, }).then((willDelete) => { if (willDelete) { this.$swal("メッセージを削除しました", { icon: "success", }); this.$router.go({ path: `/chat/${this.$route.params.id}`, force: true, }); } else { this.$swal("キャンセルしました。"); } }); }, }, };

#追記2
追加

#追記3

<template> <div class="chat"> <h1 class="chat-tll flex"> <div class="flash neon">Chat Room</div> <router-link :to="`/board/${this.uid}`" class="back-btn"> <img src="../assets/戻る.jpg" alt="チャット終了" class="back-btn-icon" /> </router-link> </h1> <!--Firebase から取得したリストを描画--> <transition-group name="chat" tag="div" class="list content"> <!--chatの中の{ key, name, image, message ,userid }をそれぞれ取得--> <section v-for="{ key, name, image, message, userid, time } in chat" :key="key" > <div v-if="userid === user.uid" class="myitem flex"> <!-- 自身 --> <!--「画像」の指定--> <!--「名前」と「メッセージ」の指定--> <div class="mydetail"> <div class="mytime">{{ $dayjs(time).format("hh:mm") }}</div> <div @click.right.prevent="deleteMessage(key)" class="mymessage"> <nl2br tag="div" :text="message" /> </div> </div> <div class="myimage flex"> <img :src="image" width="40" height="40" /> <div class="myname">{{ profileDeta.name }}</div> </div> </div> <div v-else class="otheritem flex"> <!-- 自身ではない --> <!--「画像」の指定--> <div class="otherimage flex"> <img :src="image" width="40" height="40" /> <div class="othername">name</div> </div> <!--「名前」と「メッセージ」の指定--> <div class="otherdetail"> <div class="othermessage"> <nl2br tag="div" :text="message" /> </div> <div class="othertime">{{ $dayjs(time).format("hh:mm") }}</div> </div> </div> </section> </transition-group>

#追記4

<div @click.right.prevent="deleteMessage(key)" class="mymessage"> {{key}} <nl2br tag="div" :text="message" /> </div>
deleteMessage(key) { console.log(key); firebase .database() .ref() .remove(); this.$swal({ title: "内容確認", text: "メッセージを削除しますか?", icon: "warning", buttons: true, dangerMode: true, }).then((willDelete) => { if (willDelete) { this.$swal("メッセージを削除しました", { icon: "success", }); this.$router.go({ path: `/chat/${this.$route.params.id}`, force: true, }); } else { this.$swal("キャンセルしました。"); } }); },

画像

画像

#追記5

{ path: "/chat/:id", name: "Chat", component: Chat, meta: { requiresAuth: true }, },
deleteMessage(key) { firebase .database() .ref("${this.$route.params.id}/key") .remove();

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

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

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

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

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

K_3578

2021/05/14 01:32

なんで何度も言われてるのにマルチポストするのか。 見た感じいっつもQiitaに回答付いてないし要らなくない?とは思った。
TMTN

2021/05/14 02:09

K_3578様 ご指摘ありがとうございます。 対応済です。ご迷惑お掛けして大変申し訳ございませんでした。
K_3578

2021/05/14 02:10

別に削除しろって事じゃないですよ、マルチポストするならルールを守ってマルチポストしてください。
TMTN

2021/05/14 02:15

承知しました。 恥ずかしながらマルチポストの意味すら分かっていないままでした。 調べることもしないでそのままにしてしまい申し訳ございません。
K_3578

2021/05/14 02:22

後、これは忠告ですが 基本的に質問は1個ずつの方が良いです。 teratailは限られた回答者が多くの質問に答えている事が殆どなので、 回答者は無限にいるわけじゃないです。 その中で質問者さんは同じようなタイトルで質問を連投していますから、 ある程度常駐されている方なら「こいつまた連投してる、マナー悪いな」と思われるでしょう。 丸投げであったり、プログラミングと関係ない質問よりはマシですが、悪い印象が付いて 回答を敬遠されるでしょうから。 一気に解決しようとするより一つずつ確実に問題解決した方が結果的に早くなります。 以上、長文失礼しました。
TMTN

2021/05/14 02:31

アドバイスありがとうございます。 自分で調べず質問を丸投げは一切しておりませんが、自分一人で何度も調べても分からない箇所がいくつか出てきてその分からなかった点をまとめて解決したいという考えとなってしましました。 回答者の立場になって考えると時間を割いてまで自身の質問に回答を頂いているわけなので 同じ質問者がいくつも連投していると悪い印象を与えてしまいますよね・・おっしゃり通りです。 大変申し訳ございませんでした。 テラテイル様にはとても助けられていますので以後気を付けて投稿致します。
K_3578

2021/05/14 02:33

アドバイスを受け入れて頂けるだけでこちらとしても有難い限りです。 (大抵逆ギレされるか無視されるので・・・。)
TMTN

2021/05/14 02:41

とんでもないです。 ご指摘いただいているのにも関わらず調べずにそのままにしていたのは私なので・・ 本当にご迷惑お掛けして申し訳ございませんでした。 今後は規定を理解した上で投稿するように致します。
guest

回答1

0

ベストアンサー

追記ありがとうございます!
やはりkeyでしたね。

そのままdeleteMessage(key)としてもエラーになると思います。

vue

1<div @click.right.prevent="deleteMessage" class="mymessage"> 2 <nl2br tag="div" :text="message" /> 3</div>

ここはvueのhtml側の nl2br はコンポーネントを呼び出してると思うのですが、
今のままだと、divの@clickイベントと nl2brが連動してないです。

このあたりを見ていただいて、連動させるか、
v-slotの解説

コンポーネントで呼ぶのではなく、dataの中のchatをv-forで表示するといった方法もありです。

vue

1 2//↓このchatは、dataにあるthis.chatです。 3//this.chatには幾つかのメッセージがあるはずなので、それをitemに代入しています。 4 5<div v-for="(item ,index) in chat" :key=index> 6 <div @click.right.prevent="deleteMessage(item.key)" class="mymessage"> 7 {{item.message}} 8 </div> 9</div>

こうすることで、deleteMessage(key)のkeyには、それぞれのメッセージ固有のkeyが渡されていますので、
refにpath入ります。
※実際には、親のkeyも 必要になるとは思いますが。

vue

1deleteMessage(key) { 2 3 var path = "V5S2...." +key //親のKey +当該メッセージのkey 4  5 firebase 6  .database() 7  .ref(path) 8//・・・・

もし、言っている内容がちょっと難しいと感じるようでしたら、先にvueでいくつかサイトを作ってみてもいいと思います!
今作っている内容はまあまあ中級なので、vueの理解が無いとこの先辛くなってくると思います。

これは余談ですが、vueのレイアウトは(htmlとCSS)、vuetifyを導入するとかなり楽になりますよ。
CSSを書くことがすごく減ります。


すみません、databaseを試せるものがないので、想像でのお答えになってしまいますが。。。

これは、DBに値が追加された時に呼び出される関数ですか?
この、key: snap.key,はrefのkeyじゃないのでしょうか?

取得したきた値全てを一度console.logか何かでチェックしてみるとrefと同じ値が見つかりますので、
それをchat等の変数に入れておき、deleteMessageの引数として渡せば、デリートの際にrefが指定できると思います。

removeのリファレンス

vue

1 childAdded(snap) { 2 //snapshotとは、ある時点における特定のデータベース参照にあるデータの全体像を写し取ったもの 3 //childAdded:データベースからアイテムのリストを取得する関数 4 // 受け取ったメッセージをchatに追加 5 const message = snap.val(); 6 //イベントのときにデータベース内の「message」データを取得。 7 // データベースに新しい要素が追加されると随時呼び出される 8 this.chat.push({ 9 key: snap.key, 10 name: message.name, 11 image: message.image, 12 message: message.message, 13 userid: message.userid, 14 time: message.time, 15 }); 16 this.scrollBottom(); 17 //スクロールの一番下に追加。 18 },

もっぱらfirestoreなので、少々勝手が違うのですが、

リファレンスを見る限り、このあたりで取れると思うのですが、どうでしょう?
データ読み込み時に、refのuid(key)を取得しておいて、deleteMessage関数に引数で渡せば大丈夫と
思います。

リファレンス

投稿2021/05/13 04:10

編集2021/05/13 06:42
Tatsunosuke

総合スコア599

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

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

TMTN

2021/05/13 04:24

ご回答ありがとうございます。 追記にデータ読み込み部を追加しましたが、doSend()にメソッドでpushする際にkeyを取得してdeleteMessage関数に引数で渡すということでしょうか。。 初学者のため、どのように記述すればいいのか少しわからないもので・・
TMTN

2021/05/13 06:04

これは、DBに値が追加された時に呼び出される関数ですか? ⇨追加された時に呼び出される関数になります。 この、key: snap.key,はrefのkeyじゃないのでしょうか? ⇨コンソールでchatを参照すると追加した画像のように、掲載しておりました青で囲っていたid部(key)が取得できていることを確認いたしました。 ---------------------------------------------- deleteMessage(key) { firebase .database() .ref() .remove(); this.$swal({ title: "内容確認", text: "メッセージを削除しますか?", icon: "warning", buttons: true, dangerMode: true, }).then((willDelete) => { if (willDelete) { this.$swal("メッセージを削除しました", { icon: "success", }); this.$router.go({ path: `/chat/${this.$route.params.id}`, force: true, }); } else { this.$swal("キャンセルしました。"); } }); }, ---------------------------------------------- 上記のようにするとkeyが定義されていないと出ます。 chat等の変数に入れるというのは、このdata部分に入れるということでしょうか・・ ---------------------------------------------- data() { return { user: {}, // ユーザー情報 chat: [], // 取得したメッセージを入れる配列 input: "", // 入力したメッセージ usersData: [], profileDeta: {}, }; }, ---------------------------------------------- 質問ばかり大変申し訳ございません。。
TMTN

2021/05/13 07:01

ご回答ありがとうございます。 <nl2br>とは改行タグという認識でした。 v-forを使用せずとも現在青で囲ったように固有のkeyを渡されている状態なので、 refでそのkeyを渡す記述方法がわかれば削除ができるのかなと思ったのですが、 そうとはいかないのですね・・ アドバイスありがとうございます。 vuetifyは使った方が楽ですよね。。制作しているうちに気づいたのですが、結構CSS書いた後だったため描き直すのが大変かと思いそのままにしておりました。。
Tatsunosuke

2021/05/13 07:11

そうでしたか!それは、お節介が過ぎました。。すみません。 nl2br、、あー、改行タグでしたか。 <nl2br tag="div" :text="message" /> となると、このmessageはどこと紐づいてます? どこかに親がいてそのデータを引き継いでいるはずなので、 <div @click.right.prevent="deleteMessage(key)" class="mymessage"> 入れてやればいけるんじゃないですかね?
TMTN

2021/05/13 11:20

お返事遅くなり申し訳ございません。 messageは下記に紐づいているかと思われます。 ---------------------------------------------- childAdded(snap) { //snapshotとは、ある時点における特定のデータベース参照にあるデータの全体像を写し取ったもの //childAdded:データベースからアイテムのリストを取得する関数 // 受け取ったメッセージをchatに追加 const message = snap.val(); //イベントのときにデータベース内の「message」データを取得。 // データベースに新しい要素が追加されると随時呼び出される this.chat.push({ key: snap.key, name: message.name, image: message.image, message: message.message, userid: message.userid, time: message.time, }); this.scrollBottom(); //スクロールの一番下に追加。 }, ---------------------------------------------- <div @click.right.prevent="deleteMessage(key)" class="mymessage">としてみましたが、 keyが定義されていないと出ますね。。
Tatsunosuke

2021/05/13 12:47

html側のコードを見たいので参考にされているページなど教えていただけるともう少しいろいろお伝えできるとい思います!
Tatsunosuke

2021/05/13 12:55

それっぽい記事はいくつか見つかったのですが、 他の記事ではv-forで出力しているようなので、TMTNさんが参考にされている記事では、メッセージの出力をどこから引っ張っているのか確認したいです。 > messageは下記に紐づいているかと思われます。 これはmethodsの中のchildAdded関数の中の変数なので、html側でのバインドとは連動していないと思うんですよね。 messageは、おそらく this.chat の中のmessageをバインドさせていると思います。 https://cr-vue.mio3io.com/tutorials/firebase.html#%E3%83%81%E3%83%A3%E3%83%83%E3%83%88%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E5%AE%9A%E7%BE%A9 例えば、この記事だと <section v-for="{ key, name, image, message } in chat" :key="key" class="item"> ここのfor文ででchatを回してmessageを作ってます。
TMTN

2021/05/13 13:47

HTML側を追記3に追加しました。 掲載いただいた記事を参考に作成させて頂きました。 > messageは下記に紐づいているかと思われます。 >これはmethodsの中のchildAdded関数の中の変数なので、html側でのバインドとは連動していないと思うんですよね。 >messageは、おそらく this.chat の中のmessageをバインドさせていると思います。 知識不足で申し訳ございません。確かにchildAdded関数の中の変数なので違いそうですね。。 Tatsunosuke様のおっしゃる通りthis.chat の中のmessageのようですね。
TMTN

2021/05/13 13:57

HTML欄に記載した箇所私が誤っておりました。。申し訳ございません。。
Tatsunosuke

2021/05/14 00:04

ありがとうございます! そうすると <div @click.right.prevent="deleteMessage(key)" class="mymessage"> が成り立つはずなんですが。。。 ↑この下あたりに{{key}}と入れてみていただけますか? これで値が表示されていればOk されていなければchatに代入されていないです。 <div @click.right.prevent="deleteMessage(key)" class="mymessage"> {{key}} <nl2br tag="div" :text="message" /> 次に、 method の中の deleteMessage関数を右クリックで呼び出した際に console.log(key)でkeyが問題なく引数として渡されているか 確認いただきたいです。
TMTN

2021/05/14 01:26

Tatsunosuke様 ご回答ありがとうございます。 今少し外出しておりますので夜帰宅しましたらすぐにご確認致します。 大変申し訳ございません。
TMTN

2021/05/14 02:06

1T2R3M4様 ご指摘ありがとうございます。 対応済です。大変申し訳ございませんでした。
TMTN

2021/05/14 11:59

Tatsunosuke様 お返事遅くなり申し訳ございません。 ---------------------------------------------- <div @click.right.prevent="deleteMessage(key)" class="mymessage"> <nl2br tag="div" :text="message" /> </div> ---------------------------------------------- としたら、keyがしっかりと表示されました。 また、以下もkeyをコンソールで確認しましたら値が取得されており 右クリックで削除もできるようになりました・・ ---------------------------------------------- deleteMessage(key) { console.log(key); firebase .database() .ref() .remove(); this.$swal({ title: "内容確認", text: "メッセージを削除しますか?", icon: "warning", buttons: true, dangerMode: true, }).then((willDelete) => { if (willDelete) { this.$swal("メッセージを削除しました", { icon: "success", }); this.$router.go({ path: `/chat/${this.$route.params.id}`, force: true, }); } else { this.$swal("キャンセルしました。"); } }); }, ---------------------------------------------- しかし、少しふと思ったのが、console.log(key);部分を今は記載しておりますが、 こちらを消したらまた値(key)が定義されていないと言われます・・ こういった場合、皆さんはどのように記述しているのでしょうか。。 最後の最後にご質問失礼します・・
TMTN

2021/05/14 12:17

Tatsunosuke様 大変申し訳ございません。 追記4に追加しましたのですが、{{key}}で表示した値とconsole.log(key);で出力させた値を 画像1枚目で同じ色で囲っているのですが、間違いなく同じ値を取れているのですが、 右クリックで削除した際に、全てのchatルームのメッセージが削除されてしまいました。。 (2枚目のようにnullとなってしまいました。。) 原因を調べてみたのですが、分からずです・・・
TMTN

2021/05/14 12:24

ref()となっていたので.ref(this.$route.params.id)としましたが、 それでもそのチャットルーム内の全てのメッセージが削除されてしまいます・・
Tatsunosuke

2021/05/14 12:41

console.log(key); firebase .database() .ref() ここ.ref()に削除したいメッセージのパスを入れるはずですが、ここにkeyを入れてないのですか? .ref(key) でいけると思います。 > 定義されていないと言われます これはエラーコード何が出てますか? 未使用のエラーとかではないですか? 全部消えたのは、ref()が指定されていないので全件削除されたとかではないかと思います。 .ref(this.$route.params.id) これだと、ルート上の一番上のkeyになるんじゃないですかね? なので全部消えても不思議ではないです
TMTN

2021/05/14 14:29

ここ.ref()に削除したいメッセージのパスを入れるはずですが、ここにkeyを入れてないのですか? .ref(key)でいけると思います。 ⇨そういう事ですね。。下記のようにしましたが、次は何も変化しなくなってしまいました。。 deleteMessage(key) { firebase .database() .ref(key) .remove(); console.log(key); 上記でkeyの値も確認しましたが値は取れています。。 ---------------------------------------------- deleteMessage(key) { firebase .database() .ref(key) .remove(); console.log(key); this.$swal({ title: "内容確認", text: "メッセージを削除しますか?", icon: "warning", buttons: true, dangerMode: true, }).then((willDelete) => { if (willDelete) { this.$swal("メッセージを削除しました", { icon: "success", }); this.$router.go({ path: `/chat/${this.$route.params.id}`, force: true, }); } else { this.$swal("キャンセルしました。"); } }); }, ----------------------------------------------
Tatsunosuke

2021/05/14 14:36

databaseのデリートの仕組みがわからないので あれなんですが、親のキーを入れてやる必要があるかもしれません。 例)親のkey = "abcdefg" メッセージのkey ="1234567" ref("abcdefg/1234567") 前に載せたやつです↓ deleteMessage(key) { var path = "V5S2...." +key //親のKey +当該メッセージのkey   firebase   .database()   .ref(path) //・・・・
TMTN

2021/05/14 14:51

追記5に追加したのですが、routerにパラメーターの設定をしているので、 .ref("${this.$route.params.id}/key")という風にしたのですが、記述の方法がダメなんですかね。。 ちなみにURLのidに親要素を入れているのでこれでも大丈夫かなと思ったのですが・・
Tatsunosuke

2021/05/14 14:56 編集

そしたら、これでいけませんか? .ref(this.$route.params.id+"/"+key)
TMTN

2021/05/14 15:09

Tatsunosuke様 .ref(this.$route.params.id+"/"+key)とすることでやっと上手く動きました・・ 本当に長い時間お付き合い頂きましてありがとうございました。 助かりました。。
Tatsunosuke

2021/05/14 15:26

おお!!よかった!! これで心置きなく眠れます笑 完成まで頑張ってくださいね!!
TMTN

2021/05/14 15:46

本当にありがとうございました・・ 完成まで踏ん張って頑張ります!! 何度も申し上げますが、本当にありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問