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

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

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

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

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

4404閲覧

Vueの単一ファイルコンポーネントで、データの受け渡しができない

moke

総合スコア2241

Vue.js

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

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2017/06/06 09:33

###前提・実現したいこと

Rails 5.1で作るVue.jsアプリケーションを参考にRails5.1 + webpack + vue.jsでアプリケーションを作成しているのですが。
Rails5.1の正式リリースから単一ファイルのコンポーネントの使用がデフォルトになったため,うまく動かないようなので、
上記内容を単一ファイルのコンポーネントで書き換えたいと思っています。

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

Error in data(): "TypeError: Cannot read property 'forEach' of undefined"

①の部分を消した場合。

[Vue warn]: Unknown custom element: <demo-grid> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

###該当のソースコード
app.js

javascript

1import Vue from 'vue' 2import Vuex from 'vuex' 3import App from './app.vue' 4import DemoGrid from './demo-grid.vue' 5//import 'vue-turbolinks' 6//window.addEventListener('turbolinks:load', function(){ 7Vue.use(Vuex); 8document.addEventListener('DOMContentLoaded',function(){ 9new Vue(App).$mount('#demo'); 10new Vue(DemoGrid).$mount('demo-grid'); 11});

app.vue

html

1<template> 2<div id="demo"> 3<form id="search"> 4Search <input name="query" v-model="searchQuery"> 5</form> 6<demo-grid 7v-bind:data="gridData" 8v-bind:columns="gridColumns" 9v-bind:filter-key="searchQuery"> 10</demo-grid> 11</div> 12</template> 13 14<script> 15module.exports = { 16 el: '#demo', 17 data: { 18 searchQuery: '', 19 gridColumns: ['name', 'power'], 20 gridData: [ 21 { name: 'Chuck Norris', power: Infinity }, 22 { name: 'Bruce Lee', power: 9000 }, 23 { name: 'Jackie Chan', power: 7000 }, 24 { name: 'Jet Li', power: 8000 } 25 ] 26 } 27}; 28 29</script> 30 31<style scoped> 32 33</style>

demo-grid.vue

html

1<template> 2 <table> 3 <thead> 4 <tr> 5 <th v-for="key in columns" 6 @click="sortBy(key)" 7 :class="{ active: sortKey == key }"> 8 {{ key | capitalize }} 9 <span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'"> 10 </span> 11 </th> 12 </tr> 13 </thead> 14 <tbody> 15 <tr v-for="entry in filteredData"> 16 <td v-for="key in columns"> 17 {{entry[key]}} 18 </td> 19 </tr> 20 </tbody> 21 </table> 22</template> 23<script> 24module.exports = { 25 props: { 26 data: Array, 27 columns: Array, 28 filterKey: String 29 }, 30 data: function () { 31 var sortOrders = {} 32 this.columns.forEach(function (key) {//①ここを抜くと値のないdemo-gridがhtmlとして描画される。 33 sortOrders[key] = 1 34 }) 35 return { 36 sortKey: '', 37 sortOrders: sortOrders 38 } 39 }, 40 computed: { 41 filteredData: function () { 42 var sortKey = this.sortKey 43 var filterKey = this.filterKey && this.filterKey.toLowerCase() 44 var order = this.sortOrders[sortKey] || 1 45 var data = this.data 46 if (filterKey) { 47 data = data.filter(function (row) { 48 return Object.keys(row).some(function (key) { 49 return String(row[key]).toLowerCase().indexOf(filterKey) > -1 50 }) 51 }) 52 } 53 if (sortKey) { 54 data = data.slice().sort(function (a, b) { 55 a = a[sortKey] 56 b = b[sortKey] 57 return (a === b ? 0 : a > b ? 1 : -1) * order 58 }) 59 } 60 return data 61 } 62 }, 63 filters: { 64 capitalize: function (str) { 65 return str.charAt(0).toUpperCase() + str.slice(1) 66 } 67 }, 68 methods: { 69 sortBy: function (key) { 70 this.sortKey = key 71 this.sortOrders[key] = this.sortOrders[key] * -1 72 } 73 } 74}; 75 76</script> 77 78<style scoped> 79body { 80font-family: Helvetica Neue, Arial, sans-serif; 81font-size: 14px; 82color: #444; 83} 84 85table { 86border: 2px solid #42b983; 87border-radius: 3px; 88background-color: #fff; 89} 90 91th { 92background-color: #42b983; 93color: rgba(255,255,255,0.66); 94cursor: pointer; 95-webkit-user-select: none; 96-moz-user-select: none; 97-ms-user-select: none; 98user-select: none; 99} 100 101td { 102background-color: #f9f9f9; 103} 104 105th, td { 106min-width: 120px; 107padding: 10px 20px; 108} 109 110th.active { 111color: #fff; 112} 113 114th.active .arrow { 115opacity: 1; 116} 117 118.arrow { 119display: inline-block; 120vertical-align: middle; 121width: 0; 122height: 0; 123margin-left: 5px; 124opacity: 0.66; 125} 126 127.arrow.asc { 128border-left: 4px solid transparent; 129border-right: 4px solid transparent; 130border-bottom: 4px solid #fff; 131} 132 133.arrow.dsc { 134border-left: 4px solid transparent; 135border-right: 4px solid transparent; 136border-top: 4px solid #fff; 137} 138</style> 139

###試したこと
とりあえず、vue公式を一通り読んで、下記のサイトを参考に色々、置き換えて見ましたが、データの受け渡しが全くうまくいっていないようです。
一応参考にしたサイトたち
単一ファイルのコンポーネント間通信
vue.jsのcomponentをwebpackで.vueにして単一ファイルコンポーネントにする
Vue.js初心者向け:インラインテンプレートから単一ファイルコンポーネントの使い方まで

###補足情報(言語/FW/ツール等のバージョンなど)
rails5.1.1
vue.js 2.3.3

方針やヒントだけでも構わないので、情報をいただけると嬉しいです。

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

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

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

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

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

guest

回答1

0

自己解決

自己解決しました。
単一ファイルコンポーネントを親子にして
読み込ませるだけです。
turbolinksとの相性もいいですし、Rails5.1軽くて素直なvueで決まりです。

app.vue

html

1<template> 2<div id="demo"> 3<form id="search"> 4Search <input name="query" v-model="searchQuery"> 5</form> 6<demo-grid 7:data="gridData" 8:columns="gridColumns" 9:filter-key="searchQuery"> 10</demo-grid> 11</div> 12</template> 13 14<script> 15import DemoGrid from './demo-grid.vue'; 16export default { 17 el: '#demo', 18 data: { 19 searchQuery: '', 20 gridColumns: ['name', 'power'], 21 gridData: [ 22 { name: 'Chuck Norris', power: Infinity }, 23 { name: 'Bruce Lee', power: 9000 }, 24 { name: 'Jackie Chan', power: 7000 }, 25 { name: 'Jet Li', power: 8000 } 26 ] 27 }, 28 components: {DemoGrid: DemoGrid}, 29} 30</script> 31 32<style scoped> 33 34</style> 35

demo-grid.vue

html

1<template> 2 <table> 3 <thead> 4 <tr> 5 <th v-for="key in columns" 6 @click="sortBy(key)" 7 :class="{ active: sortKey == key }"> 8 {{ key | capitalize }} 9 <span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'"> 10 </span> 11 </th> 12 </tr> 13 </thead> 14 <tbody> 15 <tr v-for="entry in filteredData"> 16 <td v-for="key in columns"> 17 {{entry[key]}} 18 </td> 19 </tr> 20 </tbody> 21 </table> 22</template> 23<script> 24export default { 25 props: { 26 data: Array, 27 columns: Array, 28 filterKey: String 29 }, 30 data: function () { 31 var sortOrders = {} 32 33 return { 34 sortKey: '', 35 sortOrders: sortOrders 36 } 37 }, 38 computed: { 39 filteredData: function () { 40 var sortKey = this.sortKey 41 var filterKey = this.filterKey && this.filterKey.toLowerCase() 42 var order = this.sortOrders[sortKey] || 1 43 var data = this.data 44 if (filterKey) { 45 data = data.filter(function (row) { 46 return Object.keys(row).some(function (key) { 47 return String(row[key]).toLowerCase().indexOf(filterKey) > -1 48 }) 49 }) 50 } 51 if (sortKey) { 52 data = data.slice().sort(function (a, b) { 53 a = a[sortKey] 54 b = b[sortKey] 55 return (a === b ? 0 : a > b ? 1 : -1) * order 56 }) 57 } 58 return data 59 } 60 }, 61 filters: { 62 capitalize: function (str) { 63 return str.charAt(0).toUpperCase() + str.slice(1) 64 } 65 }, 66 methods: { 67 sortBy: function (key) { 68 this.sortKey = key 69 this.sortOrders[key] = this.sortOrders[key] * -1 70 } 71 } 72}; 73 74</script> 75 76<style scoped> 77body { 78font-family: Helvetica Neue, Arial, sans-serif; 79font-size: 14px; 80color: #444; 81} 82 83table { 84border: 2px solid #42b983; 85border-radius: 3px; 86background-color: #fff; 87} 88 89th { 90background-color: #42b983; 91color: rgba(255,255,255,0.66); 92cursor: pointer; 93-webkit-user-select: none; 94-moz-user-select: none; 95-ms-user-select: none; 96user-select: none; 97} 98 99td { 100background-color: #f9f9f9; 101} 102 103th, td { 104min-width: 120px; 105padding: 10px 20px; 106} 107 108th.active { 109color: #fff; 110} 111 112th.active .arrow { 113opacity: 1; 114} 115 116.arrow { 117display: inline-block; 118vertical-align: middle; 119width: 0; 120height: 0; 121margin-left: 5px; 122opacity: 0.66; 123} 124 125.arrow.asc { 126border-left: 4px solid transparent; 127border-right: 4px solid transparent; 128border-bottom: 4px solid #fff; 129} 130 131.arrow.dsc { 132border-left: 4px solid transparent; 133border-right: 4px solid transparent; 134border-top: 4px solid #fff; 135} 136</style> 137

app.js

javascript

1import Vue from 'vue' 2import Vuex from 'vuex' 3import App from './app.vue' 4import DemoGrid from './demo-grid.vue' 5Vue.use(Vuex); 6document.addEventListener('DOMContentLoaded',function(){ 7// bootstrap the demo 8var cont = new Vue(App).$mount('#demo'); 9});

投稿2017/06/07 07:43

moke

総合スコア2241

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問