Reputation: 431
I have a Vue instance that has data that I am trying to access from a component that is inside another component to iterate through all values with v-for from the items inside data, in this case either banners or posts.
I have reviewed the composing components section on the vue.js website, using their posts data as an example but am unable to utilize the posts data inside my blog-post component.
I have tried adding props to the blog-post component, to the nav-home component and have tried modifying the data in my vue app instance to return all values of data and tried to add the following to the mounted property, this.$emit('posts', this.posts) without success.
Console.log(this.posts) of course returns the data, however it isn't accessible in the nested components either product-banner or blog-post when included in the nav-home component.
Vue.component('nav-home', {
props: ['posts','banners'],
template: `<div>
<h1> Home component </h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<!-- banner -->
<product-banner
v-for="banner in banners"
v-bind:key="banner.id"
v-bind:banner="banner">
</product-banner>
<!-- post -->
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post">
</blog-post>
</div>`
})
Vue.component('blog-post', {
props: ['posts'],
template: `<h3>{{posts.title}}</h3>`
})
Vue.component('product-banner', {
props: ['banner'],
template: `<div id="product-banner">
<div class="product-container">
<h2>{{banner.title}}</h2>
<p>{{banner.content}}</p>
</div>
</div>`
})
Vue.directive('focus', {
inserted: function(el) {
el.focus();
}
})
new Vue({
el: '#app',
data: {
currentNav: 'Home',
navs: ['Home'],
posts: [
{ id: 1, title: 'Title one' },
{ id: 2, title: 'Title two' },
{ id: 3, title: 'Title three' }
],
banners: [
{id: 1, title: 'Title 1', content: 'Content 1'},
{id: 2, title: 'Title 2', content: 'Content 2'},
{id: 3, title: 'Title 3', content: 'Content 3'}
]
},
computed: {
contentComponent: function() {
return 'nav-' + this.currentNav.toLowerCase()
}
},
directive: {
focus: {
inserted: function(el) {
el.focus()
}
}
}
})
@charset "utf-8";
body {
font-family: tahoma;
color:#282828;
margin: 0px;
overflow: hidden;
}
.nav {
display: flex;
width: 100%;
height: 50%;
justify-content: center;
}
.nav > nav {
padding: 20px;
align-self: center;
border: 1px solid #000000;
margin: 0 10px 0 0;
transition: background 0.2s ease-in-out;
}
.nav > nav:hover {
cursor: pointer;
background: #cecece;
}
nav.active-nav.active, .active {
background: #cecece;
}
.contentDetails {
margin: 40px;
height: 100%;
display: block;
position: absolute;
}
/* SLIDE IN OUT */
.slide-enter {
transform: translate(100%, 0%);
opacity: 1;
}
.slide-leave-to {
transform: translate(-100%, -0%);
opacity: 0;
}
.slide-leave-active,
.slide-enter-active {
position: absolute;
transition: transform 1s ease-in-out,
opacity 0.2s ease-in-out;
}
/* FLIP IT */
.flipit-enter,
.flipit-leave-to {
opacity: 0;
transform: rotateY(50deg);
}
.flipit-enter-to,
.flipit-leave {
opacity: 1;
transform: rotateY(0deg);
}
.flipit-enter-active,
.flipit-leave-active {
transition: opacity, transform 200ms ease-out;
}
/* SLIDE UP */
.slideup-enter,
.slideup-leave-to {
opacity: 0;
position: absolute;
right: -9999px
}
.slideup-enter-to,
.slideup-leave {
opacity: 1;
right: 0;
}
.slideup-enter-active,
.slideup-leave-active {
transition: right, transform 200ms ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<!-- NAVIGATION -->
<div class="nav">
<nav v-for="nav in navs"
v-bind:key="nav"
v-bind:class="['nav-button', { active: currentNav === nav }]"
v-on:click="currentNav = nav">
{{ nav }}
</nav>
</div>
<!-- CONTENT COMPONENT-->
<transition name="flipit">
<component
v-bind:is="contentComponent"
class="contentDetails">
</component>
</transition>
</div>
I am expecting to see either the product banner or blog-post displayed from the product-banner or blog-post component inside the nav-home component.
Upvotes: 0
Views: 96
Reputation: 29132
You need to pass banners
and posts
as props
to your nav-home
component too.
<component
:is="contentComponent"
class="contentDetails"
:banners="banners"
:posts="posts"
>
Vue.component('nav-home', {
props: ['banners', 'posts'],
template: `
<div>
<h1> Home component </h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<!-- banner -->
<product-banner
v-for="banner in banners"
:key="'banner' + banner.id"
:banner="banner"
/>
<!-- post -->
<blog-post
v-for="post in posts"
:key="'post' + post.id"
:post="post"
/>
</div>
`
})
Vue.component('blog-post', {
props: ['post'],
template: `<h3>{{post.title}}</h3>`
})
Vue.component('product-banner', {
props: ['banner'],
template: `
<div id="product-banner">
<div class="product-container">
<h2>{{banner.title}}</h2>
<p>{{banner.content}}</p>
</div>
</div>
`
})
new Vue({
el: '#app',
data: {
currentNav: 'Home',
navs: ['Home'],
posts: [
{
id: 1,
title: 'Title one'
},
{
id: 2,
title: 'Title two'
},
{
id: 3,
title: 'Title three'
}
],
banners: [
{
id: 1,
title: 'Title 1',
content: 'Content 1'
},
{
id: 2,
title: 'Title 2',
content: 'Content 2'
},
{
id: 3,
title: 'Title 3',
content: 'Content 3'
}
]
},
computed: {
contentComponent: function() {
return 'nav-' + this.currentNav.toLowerCase()
}
}
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
<!-- NAVIGATION -->
<div class="nav">
<nav
v-for="nav in navs"
:key="nav"
:class="['nav-button', { active: currentNav === nav }]"
@click="currentNav = nav"
>
{{ nav }}
</nav>
</div>
<!-- CONTENT COMPONENT-->
<transition name="flipit">
<component
:is="contentComponent"
class="contentDetails"
:banners="banners"
:posts="posts"
>
</component>
</transition>
</div>
I've made a few others tweaks too:
v-bind:
to :
and v-on:
to @
.key
attributes so that banners and posts wouldn't clash with each other.blog-post
from posts
to post
, updating the template accordingly.Upvotes: 1