I am creating a static website where I have tabs (a reactive property) and each of them is supposed to have many cards (a reactive property) with images and text. I get this warning:
[Vue warn]: Property or method "recipes" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option or for class-based components, by initializing the property.
What am I doing wrong?
My HTML
<main id="app">
<header>
<nav>
<ul>
<li v-for="(tab, tabName) in tabs" :key="tabName">
<button class="tab" @click="setTabActive(tabName)" :class="{'active': tabName === activeTab}">
<span class="tab-copy">{{ tabName }}</span>
<span class="tab-background">
</span>
</button>
</li>
</ul>
</nav>
</header>
<article>
<div class="container">
<transition name="fade" mode="out-in" appear :duration="500">
<tab-content v-for="(tabContent, t) in tabs" :data="tabContent" :key="'content' t" v-if="t === activeTab" inline-template>
<div class="content-wrapper">
<div class="recipes" v-for="recipe in recipes">
<a href="#" class="recipe-card__card-link"></a>
<img :src="recipe.image" alt="" class="recipe-card__image">
<div class="recipe-card__text-wrapper">
<h2 class="recipe-card__title">{{recipe.name}}</h2>
<div class="recipe-card__details-wrapper">
<p class="recipe-card__excerpt">{{recipe.body}}</p>
<a href="#" class="recipe-card__read-more">Read more <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
</div>
</tab-content>
</transition>
</div>
</article>
</main>
My Vue.js
new Vue({
el: "#app",
data: {
tabs: {
"Breakfast": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Soup": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Great Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Great Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Salad": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Amazing Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Amazing Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Main": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Dessert": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Drink": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
}
},
activeTab: "Breakfast"
},
computed: {
tabContent() {
return this.tabs[this.activeTab];
}
},
methods: {
setTabActive(tab) {
this.activeTab = tab;
}
},
components:{
'TabContent': {
props: {
data: Object,
},
},
'recipes': {
props: ['image', 'name', 'body'],
},
},
})
CodePudding user response:
You have declared 'recipes' outside of the 'data' property. Custom properties like this will not be seen in your template section.
In your recipes loop:
<div class="recipes" v-for="recipe in recipes">
Try:
<div class="recipes" v-for="recipe in tabContent.recipes">
CodePudding user response:
You can try with <div v-for="(recipe, i) in data.recipes" :key="i">
new Vue({
el: "#app",
data() {
return {
tabs: {
"Breakfast": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Soup": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Great Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Great Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Salad": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Amazing Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Amazing Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Main": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Dessert": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
},
"Drink": {
recipes : [
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
{
image: "https://images.pexels.com/photos/127513/pexels-photo-127513.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
name: "Awesome Title",
body:
"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ab nam alias architecto officia, dolores animi qui debitis incidunt eius temporibus nostrum nihil soluta commodi molestiae necessitatibus ducimus amet. Suscipit, saepe!",
},
],
}
},
activeTab: "Breakfast"
}
},
computed: {
tabContent() {
return this.tabs[this.activeTab];
}
},
methods: {
setTabActive(tab) {
this.activeTab = tab;
}
},
components:{
'TabContent': {
props: {
data: Object,
},
},
'recipes': {
props: ['image', 'name', 'body'],
},
},
})
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="app">
<header>
<nav>
<ul>
<li v-for="(tab, tabName) in tabs" :key="tabName">
<button class="tab" @click="setTabActive(tabName)" :class="{'active': tabName === activeTab}">
<span class="tab-copy">{{ tabName }}</span>
<span class="tab-background">
</span>
</button>
</li>
</ul>
</nav>
</header>
<article>
<div class="container">
<transition name="fade" mode="out-in" appear :duration="500">
<tab-content v-for="(tabContent, t) in tabs" :data="tabContent" :key="'content' t" v-if="t === activeTab" inline-template>
<div class="content-wrapper">
<div class="recipes" v-for="(recipe, i) in data.recipes" :key="i">
<a href="#" class="recipe-card__card-link"></a>
<img :src="recipe.image" alt="" class="recipe-card__image">
<div class="recipe-card__text-wrapper">
<h2 class="recipe-card__title">{{recipe.name}}</h2>
<div class="recipe-card__details-wrapper">
<p class="recipe-card__excerpt">{{recipe.body}}</p>
<a href="#" class="recipe-card__read-more">Read more <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
</div>
</tab-content>
</transition>
</div>
</article>
</main>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
What you've got currently is attempted to read this.recipes
which doesn't exist. Since the recipes array is scoped to a given tab, you just need to replace
v-for="recipe in recipes"
with
v-for="recipe in tabContent.recipes"