実現したいこと
- リスト複数の親コンポーネント(新規入力・編集)で子コンポーネント(フォーム)を共有する
- 親から子に初期データを渡す
- 子で入力受け付けを行いsubmitと同時に、親にデータを渡す
- 親でfirestore(データベース)にアクセスしてデータを追加・編集する
困っていること
- submitしてもformの値が取得できない
参考にしている資料
https://katuo-ai.com/vuejs-avoid-mutating
https://qiita.com/harhogefoo/items/7232508db1f07e6b1859
https://b1tblog.com/2019/10/03/vue-input/
やったこと
(1):v-bind.syncを使いbasic_infoを子に渡す
親↓
vue
1 <basicInfoForm 2 v-bind.sync="basic_info" 3 @submit="editBasictest" 4 @close="closeForm" 5 ></basicInfoForm>
(2)子のpropsでbasic_infoを展開。
props: { start_date: { type: String, default: "", }, end_date: { type: String, default: "", }, destination: { type: String, default: "", }, goal: { type: String, default: "", }, }
子↓ フォームに入力があった場合親に連携する(updateの部分)
vue
1<v-text-field 2 label="start from*" 3 :rules="[rules.required]" 4 :value="start_date" 5 @update="$emit('update:start_date', $event.target.start_date)">
(3)submit実行により子のデータを親側で取得する
子↓
<v-btn type="submit" color="blue darken-1" text class="mr-3" @click="$emit('submit')" >start Planning</v-btn>
親↓
vue
1 <basicInfoForm 2 v-bind.sync="basic_info" 3 @submit="editBasictest" 4 @close="closeForm" 5 ></basicInfoForm> 6 7 editBasictest() { 8 const self = this; 9 self.basic_info_dialog = !self.basic_info_dialog; 10 console.log(this.basic_info.start_date); 11 console.log(this.basic_info.end_date); 12 console.log(this.basic_info.destination); 13 console.log(this.basic_info.goal); 14 }, 15
このconsole.logの結果が、子のフォームで変更した値ではなく、
フォームを開いた時点での親から子に渡された初期値が帰ってきてしまいます。
試したこと
原因を確かめるため、以下のように変更してみたのですが解決しませんでした
(1) 子コンポーネントのtext-formの設定を変更してみた
@update="$emit('update:end_date', $event.target.end_date)"
↓
@input="$emit('update:end_date', $event.target.end_date)"
→エラーになった
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'start_date' of undefined"
(2) 子コンポーネントでsubmitした値が取れるかconsole.logで出力
<v-btn type="submit" color="blue darken-1" text class="mr-3" @click="sendBasicData" >start Planning</v-btn > sendBasicData() { console.log(this.start_date); console.log(this.end_date); console.log(this.destination); console.log(this.goal); },
→親に渡そうとした時と同様、初期値だった(そもそもsubmitで値が取れていない)
環境:
"vue": "^2.6.11",
"vuetify": "^2.2.11"
以下、コード全体
親コンポーネント
<template> <div> <v-card class="mx-5 my-5" max-width="800"> <v-img class="white--text align-end" height="200px" :src="image_src"> <v-card-title>{{ basic_info.destination }}</v-card-title> </v-img> <v-card-subtitle class="title" >{{ basic_info.start_date }} 〜 {{ basic_info.end_date }}</v-card-subtitle > <v-card-text class="text--primary"> {{ basic_info.goal }} </v-card-text> <v-card-actions> <v-spacer></v-spacer> <v-dialog v-model="basic_info_dialog" persistent max-width="600px"> <template v-slot:activator="{ on }"> <v-btn v-on="on" text>Edit</v-btn> </template> <basicInfoForm v-bind.sync="basic_info" @submit="editBasictest" @close="closeForm" ></basicInfoForm> </v-dialog> <v-btn text> <router-link v-bind:to="{ name: 'plan', params: { travel_id: travel_id } }" >Detail</router-link > </v-btn> </v-card-actions> </v-card> </div> </template> <script> import basicInfoForm from "./basicInfoForm"; export default { props: { travel_id: {}, }, components: { basicInfoForm, }, data() { return { image_src: require("../assets/stockholm.jpg"), basic_info: { destination: null, start_date: null, end_date: null, goal: null, }, basic_info_dialog: null, hasNoTravels: null, }; }, created() { this.getUserBasicData(); }, methods: { getUserBasicData: async function() { console.log(this.travel_id); const db = this.$firebase.firestore(); const info_ref = db.collection("basic_info").doc(this.travel_id); info_ref.onSnapshot((doc) => { this.basic_info = doc.data(); }); }, closeForm() { this.basic_info_dialog = !this.basic_info_dialog; }, editBasictest() { const self = this; self.basic_info_dialog = !self.basic_info_dialog; console.log(this.basic_info.start_date); console.log(this.basic_info.end_date); console.log(this.basic_info.destination); console.log(this.basic_info.goal); }, editBasicData() { const self = this; self.basic_info_dialog = !self.basic_info_dialog; // basic_infoのデータを編集 const db = this.$firebase.firestore(); const batch = db.batch(); const info_ref = db.collection("basic_info").doc(this.travel_id); batch.update(info_ref, { start_date: this.basic_info.start_date, end_date: this.basic_info.end_date, destination: this.basic_info.destination, goal: this.basic_info.goal, }); batch .commit() .then(function() { console.log(); console.log(); console.log("batch end"); return; }) .catch(function(error) { console.log(error); self.hasError = true; self.errorMessage = "batch failed"; return; }); }, }, }; </script> コード
子コンポーネント(basicInfoForm.vue)
<template> <v-card> <v-card-title> <span class="headline">add new Travel</span> </v-card-title> <v-form ref="basic_info" @submit.prevent> <v-card-text> <v-container> <v-row> <!-- https://qiita.com/fukuman/items/b0bc84081ad0d2bc522aあとでこれで直す --> <v-col cols="12" sm="6" md="4"> <v-text-field label="start from*" :rules="[rules.required]" :value="start_date" @update="$emit('update:start_date', $event.target.start_date)" > <template v-slot:append-outer> <date-picker v-model="start_date" /> </template> </v-text-field> </v-col> <v-col cols="12" sm="6" md="4"> <v-text-field label="come back on*" :rules="[rules.required]" :value="end_date" @update="$emit('update:end_date', $event.target.end_date)" > <template v-slot:append-outer> <date-picker v-model="end_date" /> </template> </v-text-field> </v-col> <v-col cols="12"> <v-text-field label="destination*" :rules="[rules.required]" :value="destination" @update="$emit('update:destination', $event.target.destination)" ></v-text-field> </v-col> <v-col cols="12"> <v-text-field label="goal" :value="goal" @update="$emit('update:goal', $event.target.goal)" ></v-text-field> </v-col> </v-row> </v-container> <small>*indicates required field</small> </v-card-text> <v-row> <v-spacer></v-spacer> <v-btn color="blue darken-1" text @click="close">close</v-btn> <v-btn type="submit" color="blue darken-1" text class="mr-3" @click="sendBasicData" >start Planning</v-btn > </v-row> </v-form> </v-card> </template> <script> import DatePicker from "./DatePicker"; export default { name: "App", components: { DatePicker, }, props: { start_date: { type: String, default: "", }, end_date: { type: String, default: "", }, destination: { type: String, default: "", }, goal: { type: String, default: "", }, }, data() { return { rules: { required: (value) => !!value || "必ず入力してください", }, }; }, methods: { close() { this.$emit("close"); }, sendBasicData() { console.log(this.start_date); console.log(this.end_date); console.log(this.destination); console.log(this.goal); }, }, }; </script>
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/08/30 08:22