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

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

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

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

JavaScript

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

解決済

v-for中に登場する「子コンポーネント」内に定義されたメソッドを、親から$refsで呼びたい。

bokupiroki
bokupiroki

総合スコア53

Vue.js

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

JavaScript

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

1回答

0評価

1クリップ

308閲覧

投稿2022/01/07 14:36

編集2022/01/09 03:41

前提・実現したいこと

  • Vue.jsで、子コンポーネント内に定義されたメソッドを親コンポーネントから呼び出したい
  • 子コンポーネントは親コンポーネントのループ内で呼び出している
  • 呼び出せずにエラーになる

具体的には、記事一覧ページに表示されている個々の記事に編集ボタンを設け、
ダイアログ上で内容を更新できるようにしようとしています。

発生している問題・エラーメッセージ

記事更新しようとすると、ブラウザで見た時にコンソールに次のようなエラーが出ます。

app.js:36742 [Vue warn]: Error in v-on handler: "TypeError: Cannot read properties of undefined (reading 'update')"

該当のソースコード

↓親コンポーネント

vue

<template> <v-card v-for="(inquiry,index) in inquiries" :key="inquiry.id" class="inquiry" flat :id="inquiry.id"> <v-toolbar color="primary" dark dense> <v-dialog max-width="90%" scrollable> <template v-slot:activator="{ on, attrs }"> <v-btn icon v-bind="attrs" v-on="on"> <v-icon>mdi-square-edit-outline</v-icon> </v-btn> </template> <template v-slot:default="dialog"> <v-card> <v-toolbar color="primary" dark>記録編集</v-toolbar> <v-card-text> <RecordForm :inquiry="inquiry" ref="RecordForm"></RecordForm> </v-card-text> <v-card-actions class="end"> <v-btn text @click="edit(index,inquiry.id)">更新</v-btn> <v-btn text @click="dialog.value = false">閉じる</v-btn> </v-card-actions> </v-card> </template> </v-dialog> </v-toolbar> </v-card> </template> <script> import RecordForm from '../layout/RecordForm' export default { components: { RecordForm, }, mounted() { axios.get('/api/inquiries/archive') .then(response => { this.inquiries = response.data.data.reverse() }) }, methods: { edit(index, id) { console.log(index) this.$refs.RecordForm[index].update(id) }, }, } </script>

↓子コンポーネント(RecordForm.vue)

vue

//js部分 <script> export default { name: 'RecordForm', props: ["inquiry"], //中略 methods: { postData(id) { let postData = { //(中略) } return postData }, update(id) { let postData = this.postData(id) axios.post('/api/inquiries/edit', postData) .then(response => { alert('更新しました。'); console.log(response); }) }, } } </script>

試したこと

ここでは省略していますが、
親コンポーネントにおけるループ外の新規投稿ボタンから「子コンポーネント内に定義された新規投稿メソッド」を呼び出すことはできました。

なのでループの場合のみ起こる現象だと考えています。

下記の記事
https://qiita.com/gigazombie/items/6f53a1de17c370787eac
を見て、

  • 親コンポーネントから子コンポーネントのメソッドを呼びたい時は$refsを使えば可能
  • v-forの引数として提供されているindexを渡す必要がある

というところまでわかったのですが、その先に進めない状態です。

どなたか知恵を貸していただきたいです。

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

Vue2
Laravel8

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

naomi3

2022/01/09 06:28

正解ではないのでここに書かせていただきますが、気になったのは、:id="inquiry.id"です。 inquiry.idの値がそのままコンポーネントのHTMLのid属性値となり、1つのHTMLで「全ての要素のid属性値」はユニークでなければなりませんが、そこは大丈夫でしょうか?
naomi3

2022/01/09 07:25

v-card要素が入れ子になっていますが、それは大丈夫ですか? 子コンポーネントの削除や入れ替えはないですか?それによってindexがずれる可能性があります。
naomi3

2022/01/09 07:33

「@click="dialog.value = false"」ダイアログのインスタンス管理は、1つだけで行っておられるかのようですが、ダイアログもv-forの中にあるので、「回数分=子コンポーネントの数」だけのインスタンスがあります。それも大丈夫ですか?
bokupiroki

2022/01/10 07:18

ありがとうございます。 :id="inquiry.id"の部分は各記事のidがそれぞれ出力されるだけなので、重複せずユニークになっています。 v-card要素が入れ子になっていますが、それは大丈夫ですか? →おそらく大丈夫です。入れ子になっていますが、子要素はボタンをクリックしたら表示されるダイアログなので。 「「@click="dialog.value = false"」ダイアログのインスタンス管理は、1つだけで行っておられるかのようですが、ダイアログもv-forの中にあるので~」 →単純にその時「true」になっているダイアログがあればとにかくfalseにして非表示にするイメージなので問題がない認識です。  実際に該当部分を削除してみても、今回の事象は解決しませんでした。
naomi3

2022/01/10 15:51

ダイアログは表示されていないときはHTML要素として存在していず、表示されるときのみ生成されるかと思います。(高々1つのみ存在) これはダイアログが含む子コンポーネントRecordFormも同様です。 ところが、子コンポーネントRecordFormがv-forの回数分だけ複数個存在しているかのようにコーディングされています。this.$refs.RecordForm[index] Developer Toolを使って、ダイアログを開くときに実際に生成されているソース中のindex,inquiry.idを確認することをお勧めします。
bokupiroki

2022/01/11 06:50

解決しました。 「子コンポーネントRecordFormがv-forの回数分だけ複数個存在しているかのようにコーディングされています。」 →これ自体は問題なかったようです。 <RecordForm :inquiry="inquiry" ref="RecordForm"></RecordForm> ここの「ref="RecordForm"」が問題だったようです。 ループ中にいくつもこのコンポーネントが登場するのに、 全部ref="RecordForm"で名前が同じなので、どれを参照すればいいかが分からず エラーが出ていたものかと思われます。 ありがとうございました。

まだ回答がついていません

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

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Vue.js

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

JavaScript

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