前提
- Vue.js 2.5.8
- Sequelize 4.22.13
- express-vueによりサーバーサイドからVue.jsへデータを渡す形
やりたかったこと
Vue.jsの特徴といえば単一ファイルコンポーネントです。
コンポーネントを細かく分けることでソースコードの見通しがよくなり、整備性もよくなります。
そこで、データベースから取得したデータをカラム数などに関係なく共通のコンポーネントで表示できないか?となりました。
普通に考えれば…
データが格納されているオブジェクトを"datas"とします。
<template>
<table>
<tr>
<td v-for="value in columns">
{{value}}
</td>
</tr>
<tr v-for="(row, index) in datas">
<td v-for="col in columns">
{{ row[col] }}
</td>
</tr>
</table>
</template>
<script>
export default {
data: function () {
return {
title: 'Sample',
}
},
props: ['datas'],
computed: {
columns: function() {
return Object.keys(this.datas[0]);
},
}
}
</script>
<style lang="css">
</style>
このように、v-forを入れ子にすれば表示されるはずです。
実際、[{id: 1, name: 'test'}, {id: 2, name: 'test2'}]
のような簡単な構造のオブジェクトではこれで正常に表示されました。
しかし…
sequelizeで取得したテーブルデータを流し込むと、
TypeError: Converting circular structure to JSON
と例外が飛ばされてしまいます。
JSON.stringifyを行う際、オブジェクトに循環参照が含まれていると表示される例外のようです。
解決策
Vue.jsに渡すオブジェクトを一度JSON.stringify
してから再度JSON.parse
します。
db.Sample.findAll().then(samples => {
const data = {
response: JSON.parse(JSON.stringify(samples))
};
const vueOptions = {
head: {
title: 'Sample'
}
};
res.renderVue('database/samples', data, vueOptions);
});
あまりきれいな解決法ではないかもしれませんが、とりあえずということで。
おわりに
原因を探るためにいろいろ調べていた時、「Vue.jsって単にconsole.log()
しただけじゃreactivegetter()
とかreactivesetter()
になって中の値表示してくれないの何とかならないのかなぁ」と思って気分転換に調べてみたら、ネットの海に「一度JSON文字列に直す」という解決法が示されていて、「もしかしていけるのでは?」と今回の件に使ってみた結果がこれです。
数時間をドブに捨てました。