vue.js Property or method is not defined – nested components

Issue

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'],
 },
},
})

Solution

You can try with <div class="recipes" 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>

Answered By – Nikola Pavicevic

Answer Checked By – Willingham (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.