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

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

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

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

Vue CLI

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

Q&A

0回答

963閲覧

子コンポーネントのinput要素に親コンポーネントから別の値を送り込んでも2度目が反映されない。

keisei-001

総合スコア15

Vue.js

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

Vue CLI

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

0グッド

0クリップ

投稿2020/01/04 07:44

問題点

子コンポーネントのinput要素に親コンポーネントから別の値を送り込んでも2度目が反映されない。

###全体的な
App.vue(親コンポーネント)

<template> <div class="todo"> <div class="container"> <TopHeader :todos="todos" :calc-day="calcDay" :remaining="remaining"></TopHeader> <div class="box"> <div class="todo-left"> <!-- todoがあるときに表示する。 --> <!-- <transition name="slide" mode="out-in"> --> <transition> <div v-if="todos.length" class="todo-container"> <div class="btns"> <!-- 完了したtodoを削除 --> <button @click="purgeItem" class="common-btn purge">purge</button> <button @click="allDelete" class="common-btn delete">all delete</button> </div> <transition-group name="slide" tag="ul" class="todo-list"> <li v-for="(todo, index) in todos" :key="todo.id"> <p class="data">Posted date:{{todo.today}}</p> <p class="deadline" :class="{hurry: todo.isDone}">dead-line:{{todo.deadline}}</p> <div class="change-btns"> <span class="edit" @click="editForm(index)">edit</span> <span class="delete" @click="deleteItem(index)">delete</span> </div> <p class="title"> <label class="text"> <input type="checkbox" class="check" v-model="todo.isDone" /> <span :class="{done: todo.isDone}">{{todo.title}}</span> </label> </p> <p class="content">{{todo.content}}</p> </li> </transition-group> </div> <!-- todoがないときに表示する。 --> <ul class="no-todo-list" v-else> <li>No todo!</li> </ul> </transition> <!-- </transition> --> </div> <!--/ todo-left --> <div class="todo-right"> <transition name="slide02" mode="out-in"> <AddForm v-if="!edit" :todos="todos" :calc-day="calcDay" :edit="edit" :show="show"></AddForm> <EditForm v-else :propsNewTitle="newTitle" :props-new-content="newContent" :props-selected="selected" :deadlines="deadlines" :edit="edit" :edit-target-task="editTargetTask" @chage-edit="edit = false" @edit-todo="editItem" ></EditForm> </transition> </div> <!-- /todo-right --> <!-- :props-edit="edit" --> </div> </div> <footer> <div class="page-top" v-scroll="handleScroll" @click="toTop">top</div> <p>Copyright © KONOIKE CONSTRUCTION CO.,LTD.All rights reserved.</p> </footer> </div> </template> <script> import TopHeader from "./component/TopHeader.vue"; import AddForm from "./component/AddForm.vue"; import EditForm from "./component/EditForm.vue"; export default { components: { TopHeader, AddForm, EditForm }, data() { return { day: "", todos: [], newTitle: "", newContent: "", selected: 0, editTargetTask: 0, show: true, deadlines: { "--": "", "Within 1 day": 1, "Within 3 days": 3, "Within 5 days": 5, "Within 10 days": 10, "Within 30 days": 30, "Within 60 days": 60, "Within 100 days": 100 }, edit: false, num: 10 }; }, computed: { // 残ったtodoの数を表示 remaining() { return this.todos.filter(function(todo) { return !todo.isDone; }); }, // 終了したtodoの数を表示 finish() { return this.todos.filter(function(todo) { return todo.isDone; }); } }, methods: { // footerのスクロールボタンのfadein handleScroll: function(evt, el) { if (window.scrollY > 200) { el.classList.add("active"); } else { el.classList.remove("active"); } }, // footerのスクロールボタンのスクロールトップ toTop: function() { var scrolled = window.pageYOffset; window.scrollTo(0, Math.floor(scrolled * 0.8)); if (scrolled > 0) { window.setTimeout(this.toTop, 20); } }, // 日付のフォーマットとtodoの締め切りを設定する日数計算の関数 calcDay(day, created_at) { var today; if (created_at == null || created_at == "") { today = new Date(); } else { today = new Date(created_at); } today.setDate(today.getDate() + day); var year = today.getFullYear(); var month = today.getMonth() + 1; day = today.getDate(); var formatDay = year + "/" + month + "/" + day; return formatDay; }, // todoの削除 deleteItem(index) { confirm("delete ok?") ? this.todos.splice(index, 1) : true; }, allDelete() { confirm("all delete ok?") ? (this.todos = []) : true; }, /* v-forのindexの値を取得して関数でターゲットとするtodoのデータを取得、 v-modelをformに設置している使ってデータの値を書き換える関数*/ editForm(index) { this.edit = true; this.newTitle = this.todos[index].title; this.newContent = this.todos[index].content; this.selected = this.todos[index].selected; this.editTargetTask = index; }, editItem(value){ if (value.title == "" || value.content == "" || value.selected == "") { window.alert("Some items have not been entered."); return false; } this.todos[this.editTargetTask].title = value.title; this.todos[this.editTargetTask].content = value.content; this.todos[this.editTargetTask].deadline = this.calcDay(value.selected, this.todos[this.editTargetTask].today), this.edit = false; }, // 終了したタスクのみ削除 purgeItem() { this.finish.length === 0 ? window.alert("No checked") : confirm("purgeItem delete ok?") ? (this.todos = this.remaining) : true; } }, // todosを監視し、データを保存させている watch: { todos: { handler() { localStorage.setItem("todos", JSON.stringify(this.todos)); }, deep: true } }, // ライフサイクルのマウントされたタイミングでtodoを呼び出す。 mounted() { this.todos = JSON.parse(localStorage.getItem("todos")) || []; } }; </script>

EditForm.vue(子コンポーネント)

<template> <form @submit.prevent="editItem"> <p class="title"> <label for="title">title</label> <input type="text" id="title" v-model="newTitle"> </p> <p>{{newTitle}}</p> <p class="content"> <label for="content">content</label> <textarea cols="30" id="content" rows=" 10" v-model="newContent"></textarea> </p> <p class="deadline"> <label for="edit-deadline">deadline</label> <select id="edit-deadline" v-model="selected" options="deadlines"> <option :value="value" v-for="(value, key) in deadlines" :key=value>{{key}}</option> </select> </p> <div class="submit"> <span @click="change" class="common-btn return">return</span> <input type="submit" class="common-btn edit" value="edit"> </div> </form><!-- /editform --> </template> <script> export default { props: {/*これはバリデーションを定義した書き方*/ propsNewTitle: String, edit: Boolean, propsNewContent: String, propsSelected: Number, deadlines: Object, editTargetTask: Number }, data(){ return { newTitle: this.propsNewTitle, newContent: this.propsNewContent, selected: this.propsSelected, } }, methods: { // 編集フォームの内容を代入し変更する。 editItem(){ this.$emit("edit-todo", { title: this.newTitle, content: this.newContent, selected: this.selected, }); }, change(){ this.$emit("chage-edit") } } } </script>

###editformの流れと問題点

editFormのメソッドを発火させて対象のタイトルなどのデータを取得
⬇️
取得した値をpropsで子のコンポーネントに渡す。
⬇️
編集をして$emitを使用して親要素に渡す。
⬇️
親のコンポーネントのeditItemメソッドを発火させて更新させる。

ここまでで出来ていると思ったのですが再度違うtodoリストの違う要素のeditボタンを押してもeditFormのフォームの値が更新されない様子。。
その後にeditの送信ボタンを押すと前に更新したリストの値が新しいリストの値に更新されるということになってしまいます。

下記の本番用をみていただければ挙動が分かるかと思います。
https://todo-app02.netlify.com/

試したこと

v-modelの値を

v-model="newTitle" ???? :value="propsNewTitle" @change="newTitle = propsNewTitle"

上記のようにv-modleを分解し、変更したりしてみました。このようにpropsの値を直接セットすると初期の表示は上手くいき、他のリストのeditボタンを押しても対象の値に表示は変更されているのですが値としては上手くセット出来ない様子です。
どうかよろしくお願いいたします。

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

本番環境
https://todo-app02.netlify.com/
git hub
https://github.com/gonta1026/vue-todo02
version
@vue/cli 4.1.1

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

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

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

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問