keshipi's blog

いつでも自分を振り返れるために書きます

Laravel 5.6とVueでtodoリスト

Laravelで作ったAPI(前回の続き)から受け取ったJSONデータをVueを使ったtodoリストで描画する

ここで作るtodoリストに変更を加えていく。

Vue.jsミニハンズオン(TODOリスト作成) - Qiita

オリジナルでは、 todoをlocalStrageに保存しているが、DBに保存するようにする。

まず、jsを移植する。

// todo-app/resources/assets/js/app.js

 window.Vue = require('vue');
 
+Vue.prototype.$http = window.axios
+
 /**
  * Next, we will create a fresh Vue application instance and attach it to
  * the page. Then, you may begin adding components to this application
  * or customize the JavaScript scaffolding to fit your unique needs.
  */
 
-Vue.component('example-component', require('./components/ExampleComponent.vue'));
+Vue.component('todo-item', {
+  props: ['name', 'is_done', 'id'],
+  template: `
+  <li class="list-complete-item">
+    <label v-bind:class="{ done: is_done }">
+      <input type="checkbox" v-model="childisChecked" v-on:change="deleteCheck"> {{ name }} 
+    </label>
+  </li>`,
+  data: function () {
+    return {
+      childisChecked: this.is_done
+    }
+  },
+  methods: {
+    deleteCheck: function () {
+      this.$emit('delete', this.childisChecked, this.id)
+    }
+  }
+})
 
-const app = new Vue({
-    el: '#app'
-});
+const vm = new Vue({
+  el: '#app',
+  data: {
+    items: [],
+    newItemTitle: '',
+  },
+  methods: {
+    loadTodo: function() {
+      this.$http.get('/api/tasks')
+      .then(res =>  {
+        this.items = res.data
+      })
+    },
+    addTodo: function(newTitle) {
+      this.$http.post('/api/tasks', { name: newTitle, is_done: false })
+      .then(res =>  {
+        this.items.push({
+          name: res.data.name,
+          is_done: res.data.is_done,
+          id: res.data.id
+        });
+        this.newItemTitle = '';
+      })
+    },
+    deleteTodo: function() {
+      let self = this;
+      this.items = this.items.filter(function (item) {
+        if ( item.is_done === true ) {
+          self.$http.delete('/api/tasks/' + item.id)
+          .then(res =>  {
+          })
+        }
+        return item.is_done === false;
+      });
+    },
+    updateCheck: function(childChecked, childIndex) {
+      for (let i = 0; i < this.items.length; i++) {
+        if (this.items[i].id === childIndex) {
+          this.items[i].is_done = childChecked;
+          break;
+        }
+      }
+    }
+  },
+  mounted: function() {
+    this.loadTodo();
+  }
+})
\ No newline at end of file

次にapp.bladeを移植する。

// todo-app/resources/views/app.blade.php

         <meta charset="utf-8">
         <meta http-equiv="X-UA-Compatible" content="IE=edge">
         <meta name="viewport" content="width=device-width, initial-scale=1">
+        <meta name="csrf-token" content="{{ csrf_token() }}">
+
         <title>Laravel</title>
+        <link rel="stylesheet" href="css/app.css">
+        <style>
+          .done {
+            text-decoration: line-through;
+          }
+          .list-complete-item {
+            transition: all 1s;
+          }
+          .list-complete-enter, .list-complete-leave-to {
+            opacity: 0;
+            transform: translateX(30px);
+          }
+          .list-complete-leave-active {
+            position: absolute;
+          }
+      </style>
     </head>
     <body>
         <div id="app">
-             <example-component></example-component>
+          <p>
+            <input type="text" placeholder="add todo item" v-model="newItemTitle" v-on:keyup.enter="addTodo(newItemTitle)">
+          </p>
+          <transition-group name="list-complete" tag="ul">
+          <todo-item v-for="item in items" v-bind="item" v-bind:key="item.id" v-on:delete="updateCheck"></todo-item>
+          </transition-group>
+          <button v-on:click="deleteTodo()">Delete</button>
         </div>
+
         <script src="js/app.js"></script>
     </body>
 </html>

ビルドする。

npm run dev

f:id:keshipi:20180524002958j:plain

f:id:keshipi:20180524003009j:plain

f:id:keshipi:20180524003020j:plain