app.vueに投稿一覧があり、その投稿の中にあるユーザーの名前をクリックしたらユーザーのページに遷移させるようにしたい。
以前静的なページをVueRouterを用いてそんな感じのことをやったので、その動的なページ版。
import Vue from 'vue/dist/vue.esm.js'
import VueRouter from 'vue-router'
import Contact from '../components/contact.vue'
import About from '../components/about_coffee_passport.vue'
Vue.use(VueRouter)
export default new VueRouter({
mode: 'history',
routes: [
{ path: '/contact', component: Contact },
{ path: '/about_coffee_passport', component: About}
],
})
before
import Vue from 'vue/dist/vue.esm.js'
import VueRouter from 'vue-router'
import Contact from '../components/contact.vue'
import About from '../components/about_coffee_passport.vue'
import User from '../components/users/user.vue';
Vue.use(VueRouter)
export default new VueRouter({
mode: 'history',
routes: [
{ path: '/contact', component: Contact },
{ path: '/about_coffee_passport', component: About},
{ path: 'user', component: User}
],
})
after
こんな感じで記述。
<router-link to="/user">
<div class="user-info-timeline">
<div v-if="drink.user_img">
<img class="user-img-timeline" v-bind:src="drink.user_img" >
</div>
<div v-else>
<img class="user-img-timeline" src ="https://images.unsplash.com/photo-1469334031218-e382a71b716b?ixid=MnwxMjA3fDB8MHxzZWFyY2h8NXx8YnJlYXV0aWZ1bCUyMGdpcmx8ZW58MHx8MHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=700&q=60">
</div>
<div class="username-timeline">
{{drink.nickname}}
</div>
</div>
</router-link>
こんな感じで記述。
import VueRouter from 'vue-router'
import router from './router/router'
Vue.use(VueRouter)
Vue.use(router)
と書いたら、
vue.runtime.esm.js:638 [Vue warn]: Error in render: "TypeError: Cannot read properties of undefined (reading 'matched')"
このようにコンソールに出力された。。。
document.addEventListener('DOMContentLoaded', () => {
const app = new Vue({
render: h => h(App),
router: router
}).$mount()
document.body.appendChild(app.$el)
console.log(app)
})
router: router
この一文を追加すればok.
このように表示された。
下準備完了したので実装。
VueRouterで違うコンポーネントを表示させているが、その際にデータの受け渡しとかの記述は必要なのか。。
こーゆー記述あったので、多分必要。
router-linkでparamsを渡すことできるっぽい。
これらを参考に、
{ path: '/user/:userId', name: 'user',component: User,
<router-link to="{name: 'user', params: {userId: drink.user.id}}">
と書いてみた。
$attrs is readonly.
とエラーがコンソールに表示された。。。
この方の記事の通りで、
hello_vue.jsでは
import Vue from 'vue'
こうやってなってるのに、、
router.js側では
import Vue from 'vue/dist/vue.esm.js'
となってる。
複数のvueインスタンスがつくられてるらしい。
environment.config.merge({
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
})
にこうやって記述したら、
vue.esm.js:648 [Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
次はこのようなエラーになった。
at app/javascript/packs/components/footer.vue
footer.vueでエラーが起こり始めた。
一旦これはとばすとして、
+import Vue from 'vue/dist/vue.esm.js'
-import Vue from 'vue'
とした。
一旦、router-viewでSPA化できたからokとして、
問題点
このように一つ押しただけなのに、全部の投稿のrouter-viewが反応してしまう。。。
<li v-for="drink in drinks" :key="drink.id" class="list" >
このように繰り返してるからねぇ。。
<router-view></router-view>
router-viewの部分に表示されるので、それをv-forの外に置けば済む。
さらなる問題点。。。
問題はユーザーの投稿だけを表示させたいにも関わらず、
```user.vue
export default {
data: function(){
return {
drinks: "drinks"
}
},
created(){
this.setDrink();
},
methods: {
setDrink: function(){
axios.get('/api/drinks')
.then(response =>(
this.drinks = response.data
))
}
}
}
```
このように書いているので、全投稿を取得してしまう。
なぜ全投稿を取得してしまうのかは割愛。
自分が今考えたロジックとしては
全投稿を取得してしまうのはしょうがないとして、
v-on@clickとかなんかで、クリックした要素のuser_idを取得して、
それを子コンポーネントで渡して、
そのidと一致する投稿をthis.drinks
に代入するとか、なんとか。
ってことでクリックした要素を取得するコードを書きます。
router-linkをクリックしたら呼び出したいが、
ここにあるとおり、
このようにしないといけないらしい。
引数にdrinkを渡すことで,drink.user_idで投稿に紐付いてるユーザーのidを取得することができる。
<li v-for="drink in drinks" :key="drink.id" class="list" >
<router-link to="/user" @click.native="getUserId(drink)">
methods{
getUserId(drink){
console.log(drink)
}
雑だけど、こんな感じで書いたらいけた!!やったね!!
これをuser.vueの方に渡したい。
<router-view :user_id="user_id"></router-view>
props: {
user_id: {
type: Number
}
},
と書いたら取得できた。。やったぜ
<template>
<div>
<li v-for="drink in drinks" :key="drink.id" class="list" >
{{drink.user_id}}
</li>
</div>
</template>
<script>
import axios from 'axios';
// import likeButton from './like/likeButton.vue';
// import drinkShow from './drinks/show.vue';
export default {
props: {
user_id: {
type: Number
}
},
data: function(){
return {
drinks: "drinks"
}
},
mounted(){
this.setDrink();
},
methods: {
setDrink: function(){
axios.get('/api/drinks')
.then(response =>(
this.drinks = response.data.filter(drink =>
drink.user_id = this.user_id
)
))
}
}
}
</script>
こんな感じで書いたら、
router-link押したときに
特定の投稿のユーザーだけのidを表示できた。
mounted(){
this.setDrink();
},
methods: {
setDrink: function(){
axios.get('/api/drinks')
.then(response =>(
this.drinks = response.data.filter(drink =>
drink.user_id = this.user_id
)
))
}
}
createdからmounted()に変更
createdだと処理をするタイミングが早すぎて、this.user_idにアクセスしたときにエラーが起こってしまった。
response.dataに全投稿のデータが入ってるが、
その配列にfilter()メソッドをしてあげることで
条件に一致した要素だけで作られた配列を改めて返してくれる嬉しいメソッド。
drink.user_id(response.data、全投稿のそれぞれのuser_id)と
router-linkクリックしたときにuser.vueに渡されるuser_idが一致した要素のみを返してくれる。
つまり、クリックした投稿に紐付いてるユーザーの投稿しか表示されない!!!
やったぜ!!
って思ったけど、なぜかuser_id 5じゃない投稿もuser_idが5になっていて表示されてしまってる。
setDrink: function(){
axios.get('/api/drinks')
.then(response => {
const drinks = response.data
this.filteredDrinks = drinks.filter(drink =>
drink.user_id === this.user_id)
})
},
こんな感じで書くんだよ!!!
drink.user_id === this.user_id
にしないといけない。。。
ずっと代入式書いていた。。。
評価式にしないといけなかった。。。。
そっかぁ。。。
やっぱ基礎って大事だと思いました。
した準備は完了したので、明日はデザイン部分をやっていきたいと思いますl